Added unittests for wsgi and api.
This commit is contained in:
@@ -32,7 +32,6 @@ class API(wsgi.Router):
|
||||
|
||||
def __init__(self):
|
||||
mapper = routes.Mapper()
|
||||
mapper.connect(None, "/v1.0/{path_info:.*}",
|
||||
controller=rackspace.API())
|
||||
mapper.connect(None, "/ec2/{path_info:.*}", controller=ec2.API())
|
||||
mapper.connect("/v1.0/{path_info:.*}", controller=rackspace.API())
|
||||
mapper.connect("/ec2/{path_info:.*}", controller=ec2.API())
|
||||
super(API, self).__init__(mapper)
|
||||
|
||||
70
nova/api/test.py
Normal file
70
nova/api/test.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 OpenStack LLC.
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Test for the root WSGI middleware for all API controllers.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
import stubout
|
||||
|
||||
from nova import api
|
||||
from nova import wsgi_test
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def setUp(self): # pylint: disable-msg=C0103
|
||||
self.called = False
|
||||
self.stubs = stubout.StubOutForTesting()
|
||||
|
||||
def tearDown(self): # pylint: disable-msg=C0103
|
||||
self.stubs.UnsetAll()
|
||||
|
||||
def test_rackspace(self):
|
||||
self.stubs.Set(api.rackspace, 'API', get_api_stub(self))
|
||||
api.API()(wsgi_test.get_environ({'PATH_INFO': '/v1.0/cloud'}),
|
||||
wsgi_test.start_response)
|
||||
self.assertTrue(self.called)
|
||||
|
||||
def test_ec2(self):
|
||||
self.stubs.Set(api.ec2, 'API', get_api_stub(self))
|
||||
api.API()(wsgi_test.get_environ({'PATH_INFO': '/ec2/cloud'}),
|
||||
wsgi_test.start_response)
|
||||
self.assertTrue(self.called)
|
||||
|
||||
def test_not_found(self):
|
||||
self.stubs.Set(api.ec2, 'API', get_api_stub(self))
|
||||
self.stubs.Set(api.rackspace, 'API', get_api_stub(self))
|
||||
api.API()(wsgi_test.get_environ({'PATH_INFO': '/'}),
|
||||
wsgi_test.start_response)
|
||||
self.assertFalse(self.called)
|
||||
|
||||
|
||||
def get_api_stub(test_object):
|
||||
"""Get a stub class that verifies next part of the request."""
|
||||
|
||||
class APIStub(object):
|
||||
"""Class to verify request and mark it was called."""
|
||||
test = test_object
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
self.test.assertEqual(environ['PATH_INFO'], '/cloud')
|
||||
self.test.called = True
|
||||
|
||||
return APIStub
|
||||
17
nova/wsgi.py
17
nova/wsgi.py
@@ -83,7 +83,7 @@ class Application(object):
|
||||
raise NotImplementedError("You must implement __call__")
|
||||
|
||||
|
||||
class Middleware(Application): # pylint: disable=W0223
|
||||
class Middleware(Application):
|
||||
"""
|
||||
Base WSGI middleware wrapper. These classes require an application to be
|
||||
initialized that will be called next. By default the middleware will
|
||||
@@ -91,11 +91,11 @@ class Middleware(Application): # pylint: disable=W0223
|
||||
behavior.
|
||||
"""
|
||||
|
||||
def __init__(self, application): # pylint: disable=W0231
|
||||
def __init__(self, application): # pylint: disable-msg=W0231
|
||||
self.application = application
|
||||
|
||||
@webob.dec.wsgify
|
||||
def __call__(self, req):
|
||||
def __call__(self, req): # pylint: disable-msg=W0221
|
||||
"""Override to implement middleware behavior."""
|
||||
return self.application
|
||||
|
||||
@@ -113,7 +113,7 @@ class Debug(Middleware):
|
||||
resp = req.get_response(self.application)
|
||||
|
||||
print ("*" * 40) + " RESPONSE HEADERS"
|
||||
for (key, value) in resp.headers:
|
||||
for (key, value) in resp.headers.iteritems():
|
||||
print key, "=", value
|
||||
print
|
||||
|
||||
@@ -127,7 +127,7 @@ class Debug(Middleware):
|
||||
Iterator that prints the contents of a wrapper string iterator
|
||||
when iterated.
|
||||
"""
|
||||
print ("*" * 40) + "BODY"
|
||||
print ("*" * 40) + " BODY"
|
||||
for part in app_iter:
|
||||
sys.stdout.write(part)
|
||||
sys.stdout.flush()
|
||||
@@ -176,8 +176,9 @@ class Router(object):
|
||||
"""
|
||||
return self._router
|
||||
|
||||
@staticmethod
|
||||
@webob.dec.wsgify
|
||||
def _dispatch(self, req):
|
||||
def _dispatch(req):
|
||||
"""
|
||||
Called by self._router after matching the incoming request to a route
|
||||
and putting the information into req.environ. Either returns 404
|
||||
@@ -197,6 +198,7 @@ class Controller(object):
|
||||
must, in addition to their normal parameters, accept a 'req' argument
|
||||
which is the incoming webob.Request.
|
||||
"""
|
||||
|
||||
@webob.dec.wsgify
|
||||
def __call__(self, req):
|
||||
"""
|
||||
@@ -249,6 +251,7 @@ class Serializer(object):
|
||||
return repr(data)
|
||||
|
||||
def _to_xml_node(self, doc, metadata, nodename, data):
|
||||
"""Recursive method to convert data members to XML nodes."""
|
||||
result = doc.createElement(nodename)
|
||||
if type(data) is list:
|
||||
singular = metadata.get('plurals', {}).get(nodename, None)
|
||||
@@ -262,7 +265,7 @@ class Serializer(object):
|
||||
result.appendChild(node)
|
||||
elif type(data) is dict:
|
||||
attrs = metadata.get('attributes', {}).get(nodename, {})
|
||||
for k,v in data.items():
|
||||
for k, v in data.items():
|
||||
if k in attrs:
|
||||
result.setAttribute(k, str(v))
|
||||
else:
|
||||
|
||||
133
nova/wsgi_test.py
Normal file
133
nova/wsgi_test.py
Normal file
@@ -0,0 +1,133 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# Copyright 2010 OpenStack LLC.
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Test WSGI basics and provide some helper functions for other WSGI tests.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
import routes
|
||||
|
||||
from nova import wsgi
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def setUp(self): # pylint: disable-msg=C0103
|
||||
self.called = False
|
||||
|
||||
def test_debug(self):
|
||||
|
||||
class Application(wsgi.Application):
|
||||
"""Dummy application to test debug."""
|
||||
test = self
|
||||
|
||||
def __call__(self, environ, test_start_response):
|
||||
test_start_response("200", [("X-Test", "checking")])
|
||||
self.test.called = True
|
||||
return ['Test response']
|
||||
|
||||
app = wsgi.Debug(Application())(get_environ(), start_response)
|
||||
self.assertTrue(self.called)
|
||||
for _ in app:
|
||||
pass
|
||||
|
||||
def test_router(self):
|
||||
|
||||
class Application(wsgi.Application):
|
||||
"""Test application to call from router."""
|
||||
test = self
|
||||
|
||||
def __call__(self, environ, test_start_response):
|
||||
test_start_response("200", [])
|
||||
self.test.called = True
|
||||
return []
|
||||
|
||||
class Router(wsgi.Router):
|
||||
"""Test router."""
|
||||
|
||||
def __init__(self):
|
||||
mapper = routes.Mapper()
|
||||
mapper.connect("/test", controller=Application())
|
||||
super(Router, self).__init__(mapper)
|
||||
|
||||
Router()(get_environ({'PATH_INFO': '/test'}), start_response)
|
||||
self.assertTrue(self.called)
|
||||
self.called = False
|
||||
Router()(get_environ({'PATH_INFO': '/bad'}), start_response)
|
||||
self.assertFalse(self.called)
|
||||
|
||||
def test_controller(self):
|
||||
|
||||
class Controller(wsgi.Controller):
|
||||
"""Test controller to call from router."""
|
||||
test = self
|
||||
|
||||
def show(self, **kwargs):
|
||||
"""Mark that this has been called."""
|
||||
self.test.called = True
|
||||
self.test.assertEqual(kwargs['id'], '123')
|
||||
return "Test"
|
||||
|
||||
class Router(wsgi.Router):
|
||||
"""Test router."""
|
||||
|
||||
def __init__(self):
|
||||
mapper = routes.Mapper()
|
||||
mapper.resource("test", "tests", controller=Controller())
|
||||
super(Router, self).__init__(mapper)
|
||||
|
||||
Router()(get_environ({'PATH_INFO': '/tests/123'}), start_response)
|
||||
self.assertTrue(self.called)
|
||||
self.called = False
|
||||
Router()(get_environ({'PATH_INFO': '/test/123'}), start_response)
|
||||
self.assertFalse(self.called)
|
||||
|
||||
def test_serializer(self):
|
||||
# TODO(eday): Placeholder for serializer testing.
|
||||
pass
|
||||
|
||||
|
||||
def get_environ(overwrite={}): # pylint: disable-msg=W0102
|
||||
"""Get a WSGI environment, overwriting any entries given."""
|
||||
environ = {'SERVER_PROTOCOL': 'HTTP/1.1',
|
||||
'GATEWAY_INTERFACE': 'CGI/1.1',
|
||||
'wsgi.version': (1, 0),
|
||||
'SERVER_PORT': '443',
|
||||
'SERVER_NAME': '127.0.0.1',
|
||||
'REMOTE_ADDR': '127.0.0.1',
|
||||
'wsgi.run_once': False,
|
||||
'wsgi.errors': None,
|
||||
'wsgi.multiprocess': False,
|
||||
'SCRIPT_NAME': '',
|
||||
'wsgi.url_scheme': 'https',
|
||||
'wsgi.input': None,
|
||||
'REQUEST_METHOD': 'GET',
|
||||
'PATH_INFO': '/',
|
||||
'CONTENT_TYPE': 'text/plain',
|
||||
'wsgi.multithread': True,
|
||||
'QUERY_STRING': '',
|
||||
'eventlet.input': None}
|
||||
return dict(environ, **overwrite)
|
||||
|
||||
|
||||
def start_response(_status, _headers):
|
||||
"""Dummy start_response to use with WSGI tests."""
|
||||
pass
|
||||
14
pylintrc
14
pylintrc
@@ -1,9 +1,7 @@
|
||||
[Messages Control]
|
||||
disable=C0103
|
||||
# TODOs in code comments are fine...
|
||||
disable=W0511
|
||||
# *args and **kwargs are fine
|
||||
disable=W0142
|
||||
# W0511: TODOs in code comments are fine.
|
||||
# W0142: *args and **kwargs are fine.
|
||||
disable-msg=W0511,W0142
|
||||
|
||||
[Basic]
|
||||
# Variables can be 1 to 31 characters long, with
|
||||
@@ -14,6 +12,12 @@ variable-rgx=[a-z_][a-z0-9_]{0,30}$
|
||||
# and be lowecased with underscores
|
||||
method-rgx=[a-z_][a-z0-9_]{2,50}$
|
||||
|
||||
# Module names matching nova-* are ok (files in bin/)
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|(nova-[a-z0-9_]+))$
|
||||
|
||||
# Don't require docstrings on tests.
|
||||
no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$
|
||||
|
||||
[Design]
|
||||
max-public-methods=100
|
||||
min-public-methods=0
|
||||
|
||||
Reference in New Issue
Block a user