From 64e6e8d147f4b23693b61047e3ae17c06cc47b74 Mon Sep 17 00:00:00 2001 From: Ziad Sawalha Date: Sun, 8 May 2011 20:02:20 -0500 Subject: Minor cleanup + pep8 --- keystone/logic/service.py | 27 --------------------------- keystone/server.py | 1 - 2 files changed, 28 deletions(-) diff --git a/keystone/logic/service.py b/keystone/logic/service.py index ac87a675..c0da14e8 100644 --- a/keystone/logic/service.py +++ b/keystone/logic/service.py @@ -56,28 +56,22 @@ class IDMService(object): "with a tenant!" % duser.id) dtoken.tenant_id = duser.tenants[0].tenant_id dtoken.expires = datetime.now() + timedelta(days=1) - db_api.token_create(dtoken) return self.__get_auth_data(dtoken, duser) - def validate_token(self, admin_token, token_id, belongs_to=None): self.__validate_token(admin_token) - (dtoken, duser) = self.__get_dauth_data(token_id) if not dtoken: raise fault.ItemNotFoundFault("Token not found") - if dtoken.expires < datetime.now(): raise fault.ItemNotFoundFault("Token not found") - if belongs_to != None and dtoken.tenant_id != belongs_to: raise fault.ItemNotFoundFault("Token not found") return self.__get_auth_data(dtoken, duser) - def revoke_token(self, admin_token, token_id): self.__validate_token(admin_token) @@ -87,7 +81,6 @@ class IDMService(object): db_api.token_delete(token_id) - # # Tenant Operations # @@ -113,7 +106,6 @@ class IDMService(object): return tenant - #def get_tenants(self, admin_token, marker, limit): # self.__validate_token(admin_token) # @@ -145,20 +137,16 @@ class IDMService(object): if next: links.append(atom.Link('next', "%s?'marker=%s&limit=%s'" % (url, next, limit))) - return tenants.Tenants(ts, links) - def get_tenant(self, admin_token, tenant_id): self.__validate_token(admin_token) dtenant = db_api.tenant_get(tenant_id) if not dtenant: raise fault.ItemNotFoundFault("The tenant could not be found") - return tenants.Tenant(dtenant.id, dtenant.desc, dtenant.enabled) - def update_tenant(self, admin_token, tenant_id, tenant): self.__validate_token(admin_token) @@ -169,14 +157,10 @@ class IDMService(object): dtenant = db_api.tenant_get(tenant_id) if dtenant == None: raise fault.ItemNotFoundFault("The tenant cloud not be found") - values = {'desc': tenant.description, 'enabled': tenant.enabled} - db_api.tenant_update(tenant_id, values) - return tenants.Tenant(dtenant.id, tenant.description, tenant.enabled) - def delete_tenant(self, admin_token, tenant_id): self.__validate_token(admin_token) @@ -191,7 +175,6 @@ class IDMService(object): db_api.tenant_delete(dtenant.id) return None - # # Tenant Group Operations # @@ -219,12 +202,9 @@ class IDMService(object): dtenant.id = group.group_id dtenant.desc = group.description dtenant.tenant_id = tenant - db_api.tenant_group_create(dtenant) - return tenants.Group(dtenant.id, dtenant.desc, dtenant.tenant_id) - def get_tenant_groups(self, admin_token, tenantId, marker, limit, url): self.__validate_token(admin_token) if tenantId == None: @@ -253,7 +233,6 @@ class IDMService(object): return tenants.Groups(ts, links) - def get_tenant_group(self, admin_token, tenant_id, group_id): self.__validate_token(admin_token) @@ -267,7 +246,6 @@ class IDMService(object): return tenants.Group(dtenant.id, dtenant.desc, dtenant.tenant_id) - def update_tenant_group(self, admin_token, tenant_id, group_id, group): self.__validate_token(admin_token) @@ -297,7 +275,6 @@ class IDMService(object): return tenants.Group(group_id, group.description, tenant_id) - def delete_tenant_group(self, admin_token, tenant_id, group_id): self.__validate_token(admin_token) @@ -317,7 +294,6 @@ class IDMService(object): db_api.tenant_group_delete(group_id, tenant_id) return None - def get_users_tenant_group(self, admin_token, tenantId, groupId, marker, limit, url): self.__validate_token(admin_token) @@ -354,7 +330,6 @@ class IDMService(object): return tenants.Users(ts, links) - # # Private Operations # @@ -369,7 +344,6 @@ class IDMService(object): user = db_api.user_get(token.user_id) return (token, user) - def __get_auth_data(self, dtoken, duser): """return AuthData object for a token/user pair""" @@ -386,7 +360,6 @@ class IDMService(object): user = auth.User(duser.id, duser.tenants[0].tenant_id, groups) return auth.AuthData(token, user) - def __validate_token(self, token_id, admin=True): if not token_id: raise fault.UnauthorizedFault("Missing token") diff --git a/keystone/server.py b/keystone/server.py index 22ee8887..7758fab5 100644 --- a/keystone/server.py +++ b/keystone/server.py @@ -56,7 +56,6 @@ POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir)) if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'keystone', '__init__.py')): sys.path.insert(0, POSSIBLE_TOPDIR) -print POSSIBLE_TOPDIR import keystone.logic.service as serv import keystone.logic.types.auth as auth -- cgit From b864c54f77dc0d48480a770f5c7983a70b25c056 Mon Sep 17 00:00:00 2001 From: Ziad Sawalha Date: Sun, 8 May 2011 21:11:21 -0500 Subject: Added echod and renamed echo.py to server.py --- echo/bin/echod | 26 ++++++++ echo/echo/__init__.py | 18 +++++- echo/echo/echo.py | 163 -------------------------------------------------- echo/echo/server.py | 162 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 164 deletions(-) create mode 100755 echo/bin/echod delete mode 100644 echo/echo/echo.py create mode 100644 echo/echo/server.py diff --git a/echo/bin/echod b/echo/bin/echod new file mode 100755 index 00000000..d20a1b5e --- /dev/null +++ b/echo/bin/echod @@ -0,0 +1,26 @@ +#!/bin/sh +# Copyright (C) 2011 OpenStack LLC. +# +# 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. + +# If ../echo/__init__.py exists, add ../ to the Python search path so +# that it will override whatever may be installed in the default Python +# search path. +script_dir=`dirname $0` +if [ -f "$script_dir/../echo/__init__.py" ] +then + PYTHONPATH="$script_dir/..:$PYTHONPATH" + export PYTHONPATH +fi + +/usr/bin/env python -m echo.server $* diff --git a/echo/echo/__init__.py b/echo/echo/__init__.py index 52bcde04..3c39fdbc 100644 --- a/echo/echo/__init__.py +++ b/echo/echo/__init__.py @@ -1 +1,17 @@ -from echo import app_factory +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright (c) 2010-2011 OpenStack, LLC. +# +# 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 server import app_factory diff --git a/echo/echo/echo.py b/echo/echo/echo.py deleted file mode 100644 index e7fa38d3..00000000 --- a/echo/echo/echo.py +++ /dev/null @@ -1,163 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright (c) 2010-2011 OpenStack, LLC. -# -# 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 eventlet -from eventlet import wsgi -from lxml import etree -import os -from paste.deploy import loadapp -import sys -from webob.exc import HTTPUnauthorized - - -# If ../echo/__init__.py exists, add ../ to Python search path, so that -# it will override what happens to be installed in /usr/(local/)lib/python... -POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), - os.pardir, - os.pardir)) -if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'echo', '__init__.py')): - # also use the local keystone - KEYSTONE_TOPDIR = os.path.normpath(os.path.join(POSSIBLE_TOPDIR, - os.pardir)) - if os.path.exists(os.path.join(KEYSTONE_TOPDIR, - 'keystone', - '__init__.py')): - sys.path.insert(0, KEYSTONE_TOPDIR) - sys.path.insert(0, POSSIBLE_TOPDIR) - - -""" -Echo: a dummy service for OpenStack auth testing. It returns request info. -""" - - -class EchoApp(object): - def __init__(self, environ, start_response): - self.envr = environ - self.start = start_response - self.dom = self.toDOM(environ) - echo_xsl = os.path.join(os.path.abspath(\ - os.path.dirname(__file__)), "xsl/echo.xsl") - self.transform = etree.XSLT(etree.parse(echo_xsl)) - - def __iter__(self): - # We expect an X_AUTHORIZATION header to be passed in - # We assume the request is coming from a trusted source. Middleware - # is used to perform that validation. - if 'HTTP_X_AUTHORIZATION' not in self.envr: - self.start('401 Unauthorized', [('Content-Type', - 'application/json')]) - return iter(["401 Unauthorized"]) - - if 'HTTP_X_IDENTITY_STATUS' not in self.envr: - identity_status = "Unknown" - else: - identity_status = self.envr["HTTP_X_IDENTITY_STATUS"] - - print ' Received:' - print ' Auth Status:', identity_status - if 'HTTP_X_AUTHORIZATION' in self.envr: - print ' Identity :', self.envr['HTTP_X_AUTHORIZATION'] - if 'HTTP_X_TENANT' in self.envr: - print ' Tenant :', self.envr['HTTP_X_TENANT'] - if 'HTTP_X_GROUP' in self.envr: - print ' Group :', self.envr['HTTP_X_GROUP'] - - accept = self.envr.get("HTTP_ACCEPT", "application/json") - if accept == "application/xml": - return self.toXML() - else: - return self.toJSON() - - def toJSON(self): - self.start('200 OK', [('Content-Type', 'application/json')]) - yield str(self.transform(self.dom)) - - def toXML(self): - self.start('200 OK', [('Content-Type', 'application/xml')]) - yield etree.tostring(self.dom) - - def toDOM(self, environ): - echo = etree.Element("{http://docs.openstack.org/echo/api/v1.0}echo", - method=environ["REQUEST_METHOD"], - pathInfo=environ["PATH_INFO"], - queryString=environ.get('QUERY_STRING', "")) - content = etree.Element( - "{http://docs.openstack.org/echo/api/v1.0}content") - content.set("type", environ["CONTENT_TYPE"]) - content.text = "" - inReq = environ["wsgi.input"] - for line in inReq: - content.text = content.text + line - echo.append(content) - return echo - - -def app_factory(global_conf, **local_conf): - return EchoApp - -if __name__ == "__main__": - def usage(): - print "Runs Echo, the canonical OpenStack service, " \ - "with auth middleware" - print "Options:" - print "-h, --help : show this usage information" - print "-b, --basic : run with basic auth (uses echo_basic.ini)" - print "-r, --remote: run with remote auth on port 8100" \ - "(uses echo_remote.ini)" - print "-i, --ini filename: run with specified ini file" - print "-p, --port: specifies port to listen on (default is 8090)" - print "by default will run with local, token auth (uses echo.ini)" - - import getopt - try: - opts, args = getopt.getopt(sys.argv[1:], - "hbrp:i:", - ["help", "basic", "remote", "port", "ini"]) - except getopt.GetoptError: - usage() - sys.exit() - - port = 0 - ini = "echo.ini" - auth_name = "local Token Auth" - - for opt, arg in opts: - if opt in ["-h", "--help"]: - usage() - sys.exit() - elif opt in ["-p", "--port"]: - port = int(arg) - elif opt in ["-i", "--ini"]: - auth_name = "with custom ini: %s" % arg - ini = arg - elif opt in ["-b", "--basic"]: - auth_name = "Basic Auth" - ini = "echo_basic.ini" - elif opt in ["-r", "--remote"]: - auth_name = "remote Token Auth" - ini = "echo_remote.ini" - if not port: - port = 8100 - - if not port: - port = 8090 - print "Running with", auth_name - app = loadapp("config:" + \ - os.path.join(os.path.abspath(os.path.dirname(__file__)), - ini), global_conf={"log_name": "echo.log"}) - - wsgi.server(eventlet.listen(('', port)), app) diff --git a/echo/echo/server.py b/echo/echo/server.py new file mode 100644 index 00000000..1c65f28e --- /dev/null +++ b/echo/echo/server.py @@ -0,0 +1,162 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright (c) 2010-2011 OpenStack, LLC. +# +# 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 eventlet +from eventlet import wsgi +from lxml import etree +import os +from paste.deploy import loadapp +import sys +from webob.exc import HTTPUnauthorized + +# If ../echo/__init__.py exists, add ../ to Python search path, so that +# it will override what happens to be installed in /usr/(local/)lib/python... +POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), + os.pardir, + os.pardir)) +if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'echo', '__init__.py')): + # also use the local keystone + KEYSTONE_TOPDIR = os.path.normpath(os.path.join(POSSIBLE_TOPDIR, + os.pardir)) + if os.path.exists(os.path.join(KEYSTONE_TOPDIR, + 'keystone', + '__init__.py')): + sys.path.insert(0, KEYSTONE_TOPDIR) + sys.path.insert(0, POSSIBLE_TOPDIR) + + +""" +Echo: a dummy service for OpenStack auth testing. It returns request info. +""" + + +class EchoApp(object): + def __init__(self, environ, start_response): + self.envr = environ + self.start = start_response + self.dom = self.toDOM(environ) + echo_xsl = os.path.join(os.path.abspath(\ + os.path.dirname(__file__)), "xsl/echo.xsl") + self.transform = etree.XSLT(etree.parse(echo_xsl)) + + def __iter__(self): + # We expect an X_AUTHORIZATION header to be passed in + # We assume the request is coming from a trusted source. Middleware + # is used to perform that validation. + if 'HTTP_X_AUTHORIZATION' not in self.envr: + self.start('401 Unauthorized', [('Content-Type', + 'application/json')]) + return iter(["401 Unauthorized"]) + + if 'HTTP_X_IDENTITY_STATUS' not in self.envr: + identity_status = "Unknown" + else: + identity_status = self.envr["HTTP_X_IDENTITY_STATUS"] + + print ' Received:' + print ' Auth Status:', identity_status + if 'HTTP_X_AUTHORIZATION' in self.envr: + print ' Identity :', self.envr['HTTP_X_AUTHORIZATION'] + if 'HTTP_X_TENANT' in self.envr: + print ' Tenant :', self.envr['HTTP_X_TENANT'] + if 'HTTP_X_GROUP' in self.envr: + print ' Group :', self.envr['HTTP_X_GROUP'] + + accept = self.envr.get("HTTP_ACCEPT", "application/json") + if accept == "application/xml": + return self.toXML() + else: + return self.toJSON() + + def toJSON(self): + self.start('200 OK', [('Content-Type', 'application/json')]) + yield str(self.transform(self.dom)) + + def toXML(self): + self.start('200 OK', [('Content-Type', 'application/xml')]) + yield etree.tostring(self.dom) + + def toDOM(self, environ): + echo = etree.Element("{http://docs.openstack.org/echo/api/v1.0}echo", + method=environ["REQUEST_METHOD"], + pathInfo=environ["PATH_INFO"], + queryString=environ.get('QUERY_STRING', "")) + content = etree.Element( + "{http://docs.openstack.org/echo/api/v1.0}content") + content.set("type", environ["CONTENT_TYPE"]) + content.text = "" + inReq = environ["wsgi.input"] + for line in inReq: + content.text = content.text + line + echo.append(content) + return echo + + +def app_factory(global_conf, **local_conf): + return EchoApp + +if __name__ == "__main__": + def usage(): + print "Runs Echo, the canonical OpenStack service, " \ + "with auth middleware" + print "Options:" + print "-h, --help : show this usage information" + print "-b, --basic : run with basic auth (uses echo_basic.ini)" + print "-r, --remote: run with remote auth on port 8100" \ + "(uses echo_remote.ini)" + print "-i, --ini filename: run with specified ini file" + print "-p, --port: specifies port to listen on (default is 8090)" + print "by default will run with local, token auth (uses echo.ini)" + + import getopt + try: + opts, args = getopt.getopt(sys.argv[1:], + "hbrp:i:", + ["help", "basic", "remote", "port", "ini"]) + except getopt.GetoptError: + usage() + sys.exit() + + port = 0 + ini = "echo.ini" + auth_name = "local Token Auth" + + for opt, arg in opts: + if opt in ["-h", "--help"]: + usage() + sys.exit() + elif opt in ["-p", "--port"]: + port = int(arg) + elif opt in ["-i", "--ini"]: + auth_name = "with custom ini: %s" % arg + ini = arg + elif opt in ["-b", "--basic"]: + auth_name = "Basic Auth" + ini = "echo_basic.ini" + elif opt in ["-r", "--remote"]: + auth_name = "remote Token Auth" + ini = "echo_remote.ini" + if not port: + port = 8100 + + if not port: + port = 8090 + print "Running with", auth_name + app = loadapp("config:" + \ + os.path.join(os.path.abspath(os.path.dirname(__file__)), + ini), global_conf={"log_name": "echo.log"}) + + wsgi.server(eventlet.listen(('', port)), app) -- cgit From ae0879f5d7ee8f1704c978e57d4b462500eb927a Mon Sep 17 00:00:00 2001 From: Ziad Sawalha Date: Sun, 8 May 2011 23:23:54 -0500 Subject: Working on echo server --- README.md | 66 ++++++++++++++--------------------------------------- echo/echo/server.py | 6 +++-- 2 files changed, 21 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index df5c4fc7..0fb7c64e 100644 --- a/README.md +++ b/README.md @@ -23,23 +23,10 @@ Also included: * RemoteAuth - WSGI middleware that can be used in services (like Swift, Nova, and Glance) when Auth middleware is running remotely -DEPENDENCIES: -------------- - -* bottle -* eventlet -* lxml -* Paste -* PasteDeploy -* PasteScript -* SQLAlchemy -* SQLite3 -* webob - - -SETUP: ------- - +ENVIRONMENT & DEPENDENCIES: +--------------------------- +see pip-requires for dependency list +Setup: Install http://pypi.python.org/pypi/setuptools sudo easy_install pip sudo pip install -r pip-requires @@ -56,12 +43,12 @@ RUNNING TEST SERVICE: --------------------- Standalone stack (with Auth_Token) - $ cd echo/echo - $ python echo.py + $ cd echo/bin + $ ./echod Distributed stack (with RemoteAuth local and Auth_Token remote) - $ cd echo/echo - $ python echo.py --remote + $ cd echo/bon + $ ./echod --remote in separate session $ cd keystone/auth_protocols @@ -75,27 +62,12 @@ DEMO CLIENT: Note: this requires tests data. See section TESTING for initializing data -INSTALLING KEYSTONE: --------------------- - - $ python setup.py build - $ sudo python setup.py install - - -INSTALLING TEST SERVICE: ------------------------- - - $ cd echo - $ python setup.py build - $ sudo python setup.py install - - TESTING ------- -After starting identity.py a keystone.db sql-lite database should be created. +After starting keystone a keystone.db sqlite database should be created in the keystone folder. -To test setup the test database: +Add test data to the database: $ sqlite3 keystone/keystone.db < test/test_setup.sql @@ -109,7 +81,7 @@ To run unit tests: To run client demo (with all auth middleware running locally on sample service): - $ python echo/echo/echo.py + $ ./echo/bin/echod $ python echo/echo/echo_client.py @@ -119,7 +91,7 @@ Using SOAPUI: Download [SOAPUI](http://sourceforge.net/projects/soapui/files/): -To Test Identity Service: +To Test Keystone Service: * File->Import Project * Select tests/IdentitySOAPUI.xml @@ -128,15 +100,11 @@ To Test Identity Service: Unit Test on Identity Services ------------------------------ -In order to run the unit test on identity services, run from the keystone directory - - python server.py - -cat test_setup.sql |sqlite ../../keystone/keystone.db - -Once the Identity service is running, go to unit test/unit directory - - python test_identity.py +In order to run the unit test on identity services: +* start the keystone server +* cat test_setup.sql |sqlite ../../keystone/keystone.db +* go to unit test/unit directory +* python test_identity.py For more on unit testing please refer diff --git a/echo/echo/server.py b/echo/echo/server.py index 1c65f28e..8c24aa8f 100644 --- a/echo/echo/server.py +++ b/echo/echo/server.py @@ -22,6 +22,7 @@ from paste.deploy import loadapp import sys from webob.exc import HTTPUnauthorized + # If ../echo/__init__.py exists, add ../ to Python search path, so that # it will override what happens to be installed in /usr/(local/)lib/python... POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), @@ -158,5 +159,6 @@ if __name__ == "__main__": app = loadapp("config:" + \ os.path.join(os.path.abspath(os.path.dirname(__file__)), ini), global_conf={"log_name": "echo.log"}) - - wsgi.server(eventlet.listen(('', port)), app) + listener = eventlet.listen(('', port)) + pool = eventlet.GreenPool(1000) + wsgi.server(listener, app, custom_pool=pool) -- cgit From d32af928464afa3d1c6a233efaee3131be784761 Mon Sep 17 00:00:00 2001 From: John Eo Date: Mon, 9 May 2011 11:57:33 -0500 Subject: Adding unit test for the URL extension handler --- test/unit/test_exthandler.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 test/unit/test_exthandler.py diff --git a/test/unit/test_exthandler.py b/test/unit/test_exthandler.py new file mode 100644 index 00000000..f7c32fee --- /dev/null +++ b/test/unit/test_exthandler.py @@ -0,0 +1,35 @@ +import os +import sys +# Need to access identity module +sys.path.append(os.path.abspath(os.path.join( + os.getcwd(), '..', '..', 'keystone')) +) +from queryext.exthandler import UrlExtensionFilter +import unittest + + +class MockWsgiApp(object): + + def __init__(self): + pass + + def __call__(self, env, start_response): + pass + + +class UrlExtensionFilterTest(unittest.TestCase): + + def setUp(self): + self.filter = UrlExtensionFilter(MockWsgiApp(), {}) + + def test_xml_extension(self): + def _start_response(): + pass + env = {'PATH_INFO': '/v1.0/someresource.xml'} + self.filter(env, _start_response) + self.assertEqual('/v1.0/someresource', env['PATH_INFO']) + self.assertEqual('application/xml', env['HTTP_ACCEPT']) + + +if __name__ == '__main__': + unittest.main() -- cgit From d5ce3e52fa784c7e1f2b1a6998e38546b3727e8b Mon Sep 17 00:00:00 2001 From: John Eo Date: Mon, 9 May 2011 14:10:48 -0500 Subject: Added tests for the URL extension middleware. --- test/unit/test_exthandler.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/unit/test_exthandler.py b/test/unit/test_exthandler.py index f7c32fee..003923ff 100644 --- a/test/unit/test_exthandler.py +++ b/test/unit/test_exthandler.py @@ -17,19 +17,33 @@ class MockWsgiApp(object): pass +def _start_response(): + pass + + class UrlExtensionFilterTest(unittest.TestCase): def setUp(self): self.filter = UrlExtensionFilter(MockWsgiApp(), {}) def test_xml_extension(self): - def _start_response(): - pass env = {'PATH_INFO': '/v1.0/someresource.xml'} self.filter(env, _start_response) self.assertEqual('/v1.0/someresource', env['PATH_INFO']) self.assertEqual('application/xml', env['HTTP_ACCEPT']) + def test_json_extension(self): + env = {'PATH_INFO': '/v1.0/someresource.json'} + self.filter(env, _start_response) + self.assertEqual('/v1.0/someresource', env['PATH_INFO']) + self.assertEqual('application/json', env['HTTP_ACCEPT']) + + def test_extension_overrides_header(self): + env = {'PATH_INFO': '/v1.0/someresource.json', 'HTTP_ACCEPT': 'application/xml'} + self.filter(env, _start_response) + self.assertEqual('/v1.0/someresource', env['PATH_INFO']) + self.assertEqual('application/json', env['HTTP_ACCEPT']) + if __name__ == '__main__': unittest.main() -- cgit