test_ratelimiting.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. from synapse.api.ratelimiting import LimitExceededError, Ratelimiter
  2. from synapse.appservice import ApplicationService
  3. from synapse.types import create_requester
  4. from tests import unittest
  5. class TestRatelimiter(unittest.TestCase):
  6. def test_allowed_via_can_do_action(self):
  7. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  8. allowed, time_allowed = limiter.can_do_action(key="test_id", _time_now_s=0)
  9. self.assertTrue(allowed)
  10. self.assertEquals(10.0, time_allowed)
  11. allowed, time_allowed = limiter.can_do_action(key="test_id", _time_now_s=5)
  12. self.assertFalse(allowed)
  13. self.assertEquals(10.0, time_allowed)
  14. allowed, time_allowed = limiter.can_do_action(key="test_id", _time_now_s=10)
  15. self.assertTrue(allowed)
  16. self.assertEquals(20.0, time_allowed)
  17. def test_allowed_user_via_can_requester_do_action(self):
  18. user_requester = create_requester("@user:example.com")
  19. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  20. allowed, time_allowed = limiter.can_requester_do_action(
  21. user_requester, _time_now_s=0
  22. )
  23. self.assertTrue(allowed)
  24. self.assertEquals(10.0, time_allowed)
  25. allowed, time_allowed = limiter.can_requester_do_action(
  26. user_requester, _time_now_s=5
  27. )
  28. self.assertFalse(allowed)
  29. self.assertEquals(10.0, time_allowed)
  30. allowed, time_allowed = limiter.can_requester_do_action(
  31. user_requester, _time_now_s=10
  32. )
  33. self.assertTrue(allowed)
  34. self.assertEquals(20.0, time_allowed)
  35. def test_allowed_appservice_ratelimited_via_can_requester_do_action(self):
  36. appservice = ApplicationService(
  37. None, "example.com", id="foo", rate_limited=True, sender="@as:example.com",
  38. )
  39. as_requester = create_requester("@user:example.com", app_service=appservice)
  40. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  41. allowed, time_allowed = limiter.can_requester_do_action(
  42. as_requester, _time_now_s=0
  43. )
  44. self.assertTrue(allowed)
  45. self.assertEquals(10.0, time_allowed)
  46. allowed, time_allowed = limiter.can_requester_do_action(
  47. as_requester, _time_now_s=5
  48. )
  49. self.assertFalse(allowed)
  50. self.assertEquals(10.0, time_allowed)
  51. allowed, time_allowed = limiter.can_requester_do_action(
  52. as_requester, _time_now_s=10
  53. )
  54. self.assertTrue(allowed)
  55. self.assertEquals(20.0, time_allowed)
  56. def test_allowed_appservice_via_can_requester_do_action(self):
  57. appservice = ApplicationService(
  58. None, "example.com", id="foo", rate_limited=False, sender="@as:example.com",
  59. )
  60. as_requester = create_requester("@user:example.com", app_service=appservice)
  61. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  62. allowed, time_allowed = limiter.can_requester_do_action(
  63. as_requester, _time_now_s=0
  64. )
  65. self.assertTrue(allowed)
  66. self.assertEquals(-1, time_allowed)
  67. allowed, time_allowed = limiter.can_requester_do_action(
  68. as_requester, _time_now_s=5
  69. )
  70. self.assertTrue(allowed)
  71. self.assertEquals(-1, time_allowed)
  72. allowed, time_allowed = limiter.can_requester_do_action(
  73. as_requester, _time_now_s=10
  74. )
  75. self.assertTrue(allowed)
  76. self.assertEquals(-1, time_allowed)
  77. def test_allowed_via_ratelimit(self):
  78. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  79. # Shouldn't raise
  80. limiter.ratelimit(key="test_id", _time_now_s=0)
  81. # Should raise
  82. with self.assertRaises(LimitExceededError) as context:
  83. limiter.ratelimit(key="test_id", _time_now_s=5)
  84. self.assertEqual(context.exception.retry_after_ms, 5000)
  85. # Shouldn't raise
  86. limiter.ratelimit(key="test_id", _time_now_s=10)
  87. def test_allowed_via_can_do_action_and_overriding_parameters(self):
  88. """Test that we can override options of can_do_action that would otherwise fail
  89. an action
  90. """
  91. # Create a Ratelimiter with a very low allowed rate_hz and burst_count
  92. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  93. # First attempt should be allowed
  94. allowed, time_allowed = limiter.can_do_action(("test_id",), _time_now_s=0,)
  95. self.assertTrue(allowed)
  96. self.assertEqual(10.0, time_allowed)
  97. # Second attempt, 1s later, will fail
  98. allowed, time_allowed = limiter.can_do_action(("test_id",), _time_now_s=1,)
  99. self.assertFalse(allowed)
  100. self.assertEqual(10.0, time_allowed)
  101. # But, if we allow 10 actions/sec for this request, we should be allowed
  102. # to continue.
  103. allowed, time_allowed = limiter.can_do_action(
  104. ("test_id",), _time_now_s=1, rate_hz=10.0
  105. )
  106. self.assertTrue(allowed)
  107. self.assertEqual(1.1, time_allowed)
  108. # Similarly if we allow a burst of 10 actions
  109. allowed, time_allowed = limiter.can_do_action(
  110. ("test_id",), _time_now_s=1, burst_count=10
  111. )
  112. self.assertTrue(allowed)
  113. self.assertEqual(1.0, time_allowed)
  114. def test_allowed_via_ratelimit_and_overriding_parameters(self):
  115. """Test that we can override options of the ratelimit method that would otherwise
  116. fail an action
  117. """
  118. # Create a Ratelimiter with a very low allowed rate_hz and burst_count
  119. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  120. # First attempt should be allowed
  121. limiter.ratelimit(key=("test_id",), _time_now_s=0)
  122. # Second attempt, 1s later, will fail
  123. with self.assertRaises(LimitExceededError) as context:
  124. limiter.ratelimit(key=("test_id",), _time_now_s=1)
  125. self.assertEqual(context.exception.retry_after_ms, 9000)
  126. # But, if we allow 10 actions/sec for this request, we should be allowed
  127. # to continue.
  128. limiter.ratelimit(key=("test_id",), _time_now_s=1, rate_hz=10.0)
  129. # Similarly if we allow a burst of 10 actions
  130. limiter.ratelimit(key=("test_id",), _time_now_s=1, burst_count=10)
  131. def test_pruning(self):
  132. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  133. limiter.can_do_action(key="test_id_1", _time_now_s=0)
  134. self.assertIn("test_id_1", limiter.actions)
  135. limiter.can_do_action(key="test_id_2", _time_now_s=10)
  136. self.assertNotIn("test_id_1", limiter.actions)