diff --git a/awx/api/tests/__init__.py b/awx/api/tests/__init__.py new file mode 100644 index 0000000000..79e94eb8b3 --- /dev/null +++ b/awx/api/tests/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) 2014 Ansible, Inc. +# All Rights Reserved. + +from __future__ import absolute_import + +from .decorator_paginated import * +from .job_tasks import * diff --git a/awx/api/tests/decorator_paginated.py b/awx/api/tests/decorator_paginated.py new file mode 100644 index 0000000000..e2d3ae27c4 --- /dev/null +++ b/awx/api/tests/decorator_paginated.py @@ -0,0 +1,74 @@ +# Copyright (c) 2014 Ansible, Inc. +# All Rights Reserved. + +import json + +from django.test import TestCase + +from rest_framework.permissions import AllowAny +from rest_framework.test import APIRequestFactory +from rest_framework.views import APIView + +from awx.api.utils.decorators import paginated + + +class PaginatedDecoratorTests(TestCase): + """A set of tests for ensuring that the "paginated" decorator works + in the way we expect. + """ + def setUp(self): + self.rf = APIRequestFactory() + + # Define an uninteresting view that we can use to test + # that the paginator wraps in the way we expect. + class View(APIView): + permission_classes = (AllowAny,) + @paginated + def get(self, request, limit, offset): + return ['a', 'b', 'c', 'd', 'e'], 26 + self.view = View.as_view() + + def test_implicit_first_page(self): + """Establish that if we get an implicit request for the first page + (e.g. no page provided), that it is returned appropriately. + """ + # Create a request, and run the paginated function. + request = self.rf.get('/dummy/', {'page_size': 5}) + response = self.view(request) + + # Ensure the response looks like what it should. + r = json.loads(response.rendered_content) + self.assertEqual(r['count'], 26) + self.assertEqual(r['next'], '/dummy/?page=2&page_size=5') + self.assertEqual(r['previous'], None) + self.assertEqual(r['results'], ['a', 'b', 'c', 'd', 'e']) + + def test_mid_page(self): + """Establish that if we get a request for a page in the middle, that + the paginator causes next and prev to be set appropriately. + """ + # Create a request, and run the paginated function. + request = self.rf.get('/dummy/', {'page': 3, 'page_size': 5}) + response = self.view(request) + + # Ensure the response looks like what it should. + r = json.loads(response.rendered_content) + self.assertEqual(r['count'], 26) + self.assertEqual(r['next'], '/dummy/?page=4&page_size=5') + self.assertEqual(r['previous'], '/dummy/?page=2&page_size=5') + self.assertEqual(r['results'], ['a', 'b', 'c', 'd', 'e']) + + def test_last_page(self): + """Establish that if we get a request for the last page, that the + paginator picks up on it and sets `next` to None. + """ + # Create a request, and run the paginated function. + request = self.rf.get('/dummy/', {'page': 6, 'page_size': 5}) + response = self.view(request) + + # Ensure the response looks like what it should. + r = json.loads(response.rendered_content) + self.assertEqual(r['count'], 26) + self.assertEqual(r['next'], None) + self.assertEqual(r['previous'], '/dummy/?page=5&page_size=5') + self.assertEqual(r['results'], ['a', 'b', 'c', 'd', 'e']) diff --git a/awx/api/utils/decorators.py b/awx/api/utils/decorators.py index 79162d4b3e..a448f6b4c5 100644 --- a/awx/api/utils/decorators.py +++ b/awx/api/utils/decorators.py @@ -23,14 +23,14 @@ def paginated(method): # Manually spin up pagination. # How many results do we show? limit = api_settings.PAGINATE_BY - if request.QUERY_PARAMS.get(api_settings.PAGINATE_BY_PARAM, False): - limit = request.QUERY_PARAMS[api_settings.PAGINATE_BY_PARAM] + if request.GET.get(api_settings.PAGINATE_BY_PARAM, False): + limit = request.GET[api_settings.PAGINATE_BY_PARAM] if api_settings.MAX_PAGINATE_BY: limit = min(api_settings.MAX_PAGINATE_BY, limit) limit = int(limit) # What page are we on? - page = int(request.QUERY_PARAMS.get('page', 1)) + page = int(request.GET.get('page', 1)) offset = (page - 1) * limit # Add the limit, offset, and page variables to the keyword arguments