From 0e775d628b30f16a200d2b1f540d76ba24fbb351 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 9 Feb 2012 16:25:45 -0800 Subject: [PATCH] Add pagination to GET /tokens * Partially fixes bug 928049 Change-Id: I21943dcc7cea4dabfab672e84fe507e78e430de4 --- keystone/common/wsgi.py | 1 + keystone/identity/core.py | 31 ++++++++++++++++++-- tests/test_cli.py | 6 ++++ tests/test_keystoneclient.py | 55 ++++++++++++++++++++++++++++++++++++ tests/test_wsgi.py | 35 +++++++++++++++-------- 5 files changed, 114 insertions(+), 14 deletions(-) diff --git a/keystone/common/wsgi.py b/keystone/common/wsgi.py index ee5aac6bd6..a5ae47fcbd 100644 --- a/keystone/common/wsgi.py +++ b/keystone/common/wsgi.py @@ -165,6 +165,7 @@ class Application(BaseApplication): # allow middleware up the stack to provide context & params context = req.environ.get('openstack.context', {}) + context['query_string'] = dict(req.params.iteritems()) params = req.environ.get('openstack.params', {}) params.update(arg_dict) diff --git a/keystone/identity/core.py b/keystone/identity/core.py index 5982a7ab00..baa75947fc 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -246,7 +246,11 @@ class TenantController(wsgi.Application): tenant_refs.append(self.identity_api.get_tenant( context=context, tenant_id=tenant_id)) - return self._format_tenants_for_token(tenant_refs) + params = { + 'limit': context['query_string'].get('limit'), + 'marker': context['query_string'].get('marker'), + } + return self._format_tenant_list(tenant_refs, **params) def get_tenant(self, context, tenant_id): # TODO(termie): this stuff should probably be moved to middleware @@ -293,7 +297,30 @@ class TenantController(wsgi.Application): self.assert_admin(context) raise NotImplementedError() - def _format_tenants_for_token(self, tenant_refs): + def _format_tenant_list(self, tenant_refs, **kwargs): + marker = kwargs.get('marker') + page_idx = 0 + if marker is not None: + for (marker_idx, tenant) in enumerate(tenant_refs): + if tenant['id'] == marker: + # we start pagination after the marker + page_idx = marker_idx + 1 + break + else: + msg = 'Marker could not be found' + raise webob.exc.HTTPBadRequest(explanation=msg) + + limit = kwargs.get('limit') + if limit is not None: + try: + limit = int(limit) + assert limit >= 0 + except (ValueError, AssertionError): + msg = 'Invalid limit value' + raise webob.exc.HTTPBadRequest(explanation=msg) + + tenant_refs = tenant_refs[page_idx:limit] + for x in tenant_refs: x['enabled'] = True o = {'tenants': tenant_refs, diff --git a/tests/test_cli.py b/tests/test_cli.py index 2159e42167..04410d6e59 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -85,3 +85,9 @@ class CliMasterTestCase(test_keystoneclient.KcMasterTestCase): def test_ec2_credentials_delete_user_forbidden(self): raise nose.exc.SkipTest('cli testing code does not handle 403 well') + + def test_tenant_list_limit_bad_value(self): + raise nose.exc.SkipTest('cli testing code does not handle 400 well') + + def test_tenant_list_marker_not_found(self): + raise nose.exc.SkipTest('cli testing code does not handle 400 well') diff --git a/tests/test_keystoneclient.py b/tests/test_keystoneclient.py index 3f17cd9242..1fca22fc79 100644 --- a/tests/test_keystoneclient.py +++ b/tests/test_keystoneclient.py @@ -1,4 +1,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 + +import uuid + import nose.exc from keystone import test @@ -448,6 +451,58 @@ class KcMasterTestCase(CompatTestCase, KeystoneClientTests): self.assert_(self.tenant_baz['id'] not in [x.id for x in tenant_refs]) + def test_tenant_list_marker(self): + client = self.get_client() + + # Add two arbitrary tenants to user for testing purposes + for i in range(2): + tenant_id = uuid.uuid4().hex + tenant = {'name': 'tenant-%s' % tenant_id, 'id': tenant_id} + self.identity_api.create_tenant(tenant_id, tenant) + self.identity_api.add_user_to_tenant(tenant_id, self.user_foo['id']) + + tenants = client.tenants.list() + self.assertEqual(len(tenants), 3) + + tenants_marker = client.tenants.list(marker=tenants[0].id) + self.assertEqual(len(tenants_marker), 2) + self.assertEqual(tenants[1].name, tenants_marker[0].name) + self.assertEqual(tenants[2].name, tenants_marker[1].name) + + def test_tenant_list_marker_not_found(self): + from keystoneclient import exceptions as client_exceptions + + client = self.get_client() + self.assertRaises(client_exceptions.BadRequest, + client.tenants.list, marker=uuid.uuid4().hex) + + def test_tenant_list_limit(self): + client = self.get_client() + + # Add two arbitrary tenants to user for testing purposes + for i in range(2): + tenant_id = uuid.uuid4().hex + tenant = {'name': 'tenant-%s' % tenant_id, 'id': tenant_id} + self.identity_api.create_tenant(tenant_id, tenant) + self.identity_api.add_user_to_tenant(tenant_id, self.user_foo['id']) + + tenants = client.tenants.list() + self.assertEqual(len(tenants), 3) + + tenants_limited = client.tenants.list(limit=2) + self.assertEqual(len(tenants_limited), 2) + self.assertEqual(tenants[0].name, tenants_limited[0].name) + self.assertEqual(tenants[1].name, tenants_limited[1].name) + + def test_tenant_list_limit_bad_value(self): + from keystoneclient import exceptions as client_exceptions + + client = self.get_client() + self.assertRaises(client_exceptions.BadRequest, + client.tenants.list, limit='a') + self.assertRaises(client_exceptions.BadRequest, + client.tenants.list, limit=-1) + def test_roles_get_by_user(self): client = self.get_client() roles = client.roles.roles_for_user(user=self.user_foo['id'], diff --git a/tests/test_wsgi.py b/tests/test_wsgi.py index cf329ba734..aa2c01223e 100644 --- a/tests/test_wsgi.py +++ b/tests/test_wsgi.py @@ -1,25 +1,36 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +import json + import webob from keystone import test from keystone.common import wsgi -class FakeApp(wsgi.Application): - def index(self, context): - return {'a': 'b'} - - class ApplicationTest(test.TestCase): - def setUp(self): - self.app = FakeApp() - - def _make_request(self): - req = webob.Request.blank('/') - args = {'action': 'index', 'controller': self.app} + def _make_request(self, url='/'): + req = webob.Request.blank(url) + args = {'action': 'index', 'controller': None} req.environ['wsgiorg.routing_args'] = [None, args] return req def test_response_content_type(self): + class FakeApp(wsgi.Application): + def index(self, context): + return {'a': 'b'} + + app = FakeApp() req = self._make_request() - resp = req.get_response(self.app) + resp = req.get_response(app) self.assertEqual(resp.content_type, 'application/json') + + def test_query_string_available(self): + class FakeApp(wsgi.Application): + def index(self, context): + return context['query_string'] + + app = FakeApp() + req = self._make_request(url='/?1=2') + resp = req.get_response(app) + self.assertEqual(json.loads(resp.body), {'1': '2'})