Commit d901b1d3 by Stephen Sanchez

Allow services to ignore user throttling.

parent c8825652
...@@ -12,6 +12,8 @@ from rest_framework import status ...@@ -12,6 +12,8 @@ from rest_framework import status
from django.conf import settings from django.conf import settings
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory from xmodule.modulestore.tests.factories import CourseFactory
from course_modes.models import CourseMode
from util.models import RateLimitConfiguration
from util.testing import UrlResetMixin from util.testing import UrlResetMixin
from enrollment import api from enrollment import api
from enrollment.errors import CourseEnrollmentError from enrollment.errors import CourseEnrollmentError
...@@ -37,6 +39,11 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase): ...@@ -37,6 +39,11 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
def setUp(self): def setUp(self):
""" Create a course and user, then log in. """ """ Create a course and user, then log in. """
super(EnrollmentTest, self).setUp() super(EnrollmentTest, self).setUp()
rate_limit_config = RateLimitConfiguration.current()
rate_limit_config.enabled = False
rate_limit_config.save()
self.course = CourseFactory.create() self.course = CourseFactory.create()
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD) self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
self.other_user = UserFactory.create() self.other_user = UserFactory.create()
...@@ -276,6 +283,35 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase): ...@@ -276,6 +283,35 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("No course ", resp.content) self.assertIn("No course ", resp.content)
def test_enrollment_throttle_for_user(self):
"""Make sure a user requests do not exceed the maximum number of requests"""
rate_limit_config = RateLimitConfiguration.current()
rate_limit_config.enabled = True
rate_limit_config.save()
CourseModeFactory.create(
course_id=self.course.id,
mode_slug=CourseMode.HONOR,
mode_display_name=CourseMode.HONOR,
)
for attempt in range(0, 50):
expected_status = status.HTTP_429_TOO_MANY_REQUESTS if attempt >= 40 else status.HTTP_200_OK
self._create_enrollment(expected_status=expected_status)
def test_enrollment_throttle_for_service(self):
"""Make sure a service can call the enrollment API as many times as needed. """
rate_limit_config = RateLimitConfiguration.current()
rate_limit_config.enabled = True
rate_limit_config.save()
CourseModeFactory.create(
course_id=self.course.id,
mode_slug=CourseMode.HONOR,
mode_display_name=CourseMode.HONOR,
)
for attempt in range(0, 50):
self._create_enrollment(as_server=True)
def _create_enrollment(self, course_id=None, username=None, expected_status=status.HTTP_200_OK, email_opt_in=None, as_server=False): def _create_enrollment(self, course_id=None, username=None, expected_status=status.HTTP_200_OK, email_opt_in=None, as_server=False):
"""Enroll in the course and verify the URL we are sent to. """ """Enroll in the course and verify the URL we are sent to. """
course_id = unicode(self.course.id) if course_id is None else course_id course_id = unicode(self.course.id) if course_id is None else course_id
......
...@@ -24,12 +24,6 @@ from enrollment.errors import ( ...@@ -24,12 +24,6 @@ from enrollment.errors import (
) )
class EnrollmentUserThrottle(UserRateThrottle):
"""Limit the number of requests users can make to the enrollment API."""
# TODO Limit significantly after performance testing. # pylint: disable=fixme
rate = '50/second'
class ApiKeyPermissionMixIn(object): class ApiKeyPermissionMixIn(object):
""" """
This mixin is used to provide a convenience function for doing individual permission checks This mixin is used to provide a convenience function for doing individual permission checks
...@@ -49,6 +43,14 @@ class ApiKeyPermissionMixIn(object): ...@@ -49,6 +43,14 @@ class ApiKeyPermissionMixIn(object):
return ApiKeyHeaderPermission().has_permission(request, self) return ApiKeyHeaderPermission().has_permission(request, self)
class EnrollmentUserThrottle(UserRateThrottle, ApiKeyPermissionMixIn):
"""Limit the number of requests users can make to the enrollment API."""
rate = '40/minute'
def allow_request(self, request, view):
return self.has_api_key_permissions(request) or super(EnrollmentUserThrottle, self).allow_request(request, view)
@can_disable_rate_limit @can_disable_rate_limit
class EnrollmentView(APIView, ApiKeyPermissionMixIn): class EnrollmentView(APIView, ApiKeyPermissionMixIn):
""" """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment