django-rest-framework/djangorestframework/tests/throttling.py

140 lines
4.5 KiB
Python
Raw Normal View History

2011-06-14 14:08:29 +04:00
"""
Tests for the throttling implementations in the permissions module.
"""
from django.test import TestCase
from django.contrib.auth.models import User
from django.core.cache import cache
from djangorestframework.compat import RequestFactory
from djangorestframework.views import View
2012-08-25 01:11:00 +04:00
from djangorestframework.permissions import PerUserThrottling, PerViewThrottling
from djangorestframework.response import Response
2012-08-24 23:57:10 +04:00
class MockView(View):
2012-08-24 23:57:10 +04:00
permission_classes = (PerUserThrottling,)
throttle = '3/sec'
def get(self, request):
return Response('foo')
2012-08-24 23:57:10 +04:00
class MockView_PerViewThrottling(MockView):
2012-08-24 23:57:10 +04:00
permission_classes = (PerViewThrottling,)
class MockView_MinuteThrottling(MockView):
throttle = '3/min'
2011-12-29 17:31:12 +04:00
class ThrottlingTests(TestCase):
2011-12-29 17:31:12 +04:00
urls = 'djangorestframework.tests.throttling'
def setUp(self):
2011-06-13 22:42:37 +04:00
"""
Reset the cache so that no throttles will be active
"""
cache.clear()
self.factory = RequestFactory()
2011-12-29 17:31:12 +04:00
def test_requests_are_throttled(self):
2011-06-13 22:42:37 +04:00
"""
Ensure request rate is limited
"""
request = self.factory.get('/')
for dummy in range(4):
response = MockView.as_view()(request)
self.assertEqual(503, response.status_code)
2011-12-29 17:31:12 +04:00
2011-06-13 22:42:37 +04:00
def set_throttle_timer(self, view, value):
"""
Explicitly set the timer, overriding time.time()
"""
2012-08-24 23:57:10 +04:00
view.permission_classes[0].timer = lambda self: value
2011-06-13 22:42:37 +04:00
def test_request_throttling_expires(self):
2011-06-14 14:08:29 +04:00
"""
Ensure request rate is limited for a limited duration only
"""
2011-06-13 22:42:37 +04:00
self.set_throttle_timer(MockView, 0)
2011-06-14 14:08:29 +04:00
request = self.factory.get('/')
for dummy in range(4):
response = MockView.as_view()(request)
self.assertEqual(503, response.status_code)
2011-06-14 14:08:29 +04:00
# Advance the timer by one second
2011-06-13 22:42:37 +04:00
self.set_throttle_timer(MockView, 1)
2011-06-14 14:08:29 +04:00
response = MockView.as_view()(request)
self.assertEqual(200, response.status_code)
2011-12-29 17:31:12 +04:00
2011-06-11 22:29:01 +04:00
def ensure_is_throttled(self, view, expect):
request = self.factory.get('/')
request.user = User.objects.create(username='a')
for dummy in range(3):
2011-06-13 22:42:37 +04:00
view.as_view()(request)
request.user = User.objects.create(username='b')
response = view.as_view()(request)
2011-06-11 22:29:01 +04:00
self.assertEqual(expect, response.status_code)
2011-12-29 17:31:12 +04:00
def test_request_throttling_is_per_user(self):
2011-06-13 22:42:37 +04:00
"""
2011-12-29 17:31:12 +04:00
Ensure request rate is only limited per user, not globally for
2011-06-13 22:42:37 +04:00
PerUserThrottles
"""
2011-06-11 22:29:01 +04:00
self.ensure_is_throttled(MockView, 200)
2011-12-29 17:31:12 +04:00
def test_request_throttling_is_per_view(self):
2011-06-13 22:42:37 +04:00
"""
Ensure request rate is limited globally per View for PerViewThrottles
"""
self.ensure_is_throttled(MockView_PerViewThrottling, 503)
2011-12-29 17:31:12 +04:00
2011-06-13 22:42:37 +04:00
def ensure_response_header_contains_proper_throttle_field(self, view, expected_headers):
"""
Ensure the response returns an X-Throttle field with status and next attributes
set properly.
"""
request = self.factory.get('/')
for timer, expect in expected_headers:
self.set_throttle_timer(view, timer)
2011-06-13 22:42:37 +04:00
response = view.as_view()(request)
self.assertEquals(response['X-Throttle'], expect)
2011-12-29 17:31:12 +04:00
2011-06-13 22:42:37 +04:00
def test_seconds_fields(self):
"""
Ensure for second based throttles.
"""
self.ensure_response_header_contains_proper_throttle_field(MockView,
((0, 'status=SUCCESS; next=0.33 sec'),
(0, 'status=SUCCESS; next=0.50 sec'),
(0, 'status=SUCCESS; next=1.00 sec'),
(0, 'status=FAILURE; next=1.00 sec')
2011-06-13 22:42:37 +04:00
))
2011-12-29 17:31:12 +04:00
2011-06-13 22:42:37 +04:00
def test_minutes_fields(self):
"""
Ensure for minute based throttles.
"""
self.ensure_response_header_contains_proper_throttle_field(MockView_MinuteThrottling,
((0, 'status=SUCCESS; next=20.00 sec'),
(0, 'status=SUCCESS; next=30.00 sec'),
(0, 'status=SUCCESS; next=60.00 sec'),
(0, 'status=FAILURE; next=60.00 sec')
))
2011-12-29 17:31:12 +04:00
def test_next_rate_remains_constant_if_followed(self):
"""
If a client follows the recommended next request rate,
the throttling rate should stay constant.
"""
self.ensure_response_header_contains_proper_throttle_field(MockView_MinuteThrottling,
((0, 'status=SUCCESS; next=20.00 sec'),
(20, 'status=SUCCESS; next=20.00 sec'),
(40, 'status=SUCCESS; next=20.00 sec'),
(60, 'status=SUCCESS; next=20.00 sec'),
(80, 'status=SUCCESS; next=20.00 sec')
2011-06-13 22:42:37 +04:00
))