Merge pull request #7407 from edx/sanchez/server-to-server-throttling
Allow services to ignore user throttling. Set a more realistic throttle for users.
This commit is contained in:
@@ -12,6 +12,8 @@ from rest_framework import status
|
||||
from django.conf import settings
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from course_modes.models import CourseMode
|
||||
from util.models import RateLimitConfiguration
|
||||
from util.testing import UrlResetMixin
|
||||
from enrollment import api
|
||||
from enrollment.errors import CourseEnrollmentError
|
||||
@@ -37,6 +39,11 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
|
||||
def setUp(self):
|
||||
""" Create a course and user, then log in. """
|
||||
super(EnrollmentTest, self).setUp()
|
||||
|
||||
rate_limit_config = RateLimitConfiguration.current()
|
||||
rate_limit_config.enabled = False
|
||||
rate_limit_config.save()
|
||||
|
||||
self.course = CourseFactory.create()
|
||||
self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD)
|
||||
self.other_user = UserFactory.create()
|
||||
@@ -276,6 +283,35 @@ class EnrollmentTest(ModuleStoreTestCase, APITestCase):
|
||||
self.assertEqual(resp.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
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):
|
||||
"""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
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
This mixin is used to provide a convenience function for doing individual permission checks
|
||||
@@ -49,6 +43,14 @@ class ApiKeyPermissionMixIn(object):
|
||||
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
|
||||
class EnrollmentView(APIView, ApiKeyPermissionMixIn):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user