test_ratelimiting.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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,
  38. "example.com",
  39. id="foo",
  40. rate_limited=True,
  41. sender="@as:example.com",
  42. )
  43. as_requester = create_requester("@user:example.com", app_service=appservice)
  44. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  45. allowed, time_allowed = limiter.can_requester_do_action(
  46. as_requester, _time_now_s=0
  47. )
  48. self.assertTrue(allowed)
  49. self.assertEquals(10.0, time_allowed)
  50. allowed, time_allowed = limiter.can_requester_do_action(
  51. as_requester, _time_now_s=5
  52. )
  53. self.assertFalse(allowed)
  54. self.assertEquals(10.0, time_allowed)
  55. allowed, time_allowed = limiter.can_requester_do_action(
  56. as_requester, _time_now_s=10
  57. )
  58. self.assertTrue(allowed)
  59. self.assertEquals(20.0, time_allowed)
  60. def test_allowed_appservice_via_can_requester_do_action(self):
  61. appservice = ApplicationService(
  62. None,
  63. "example.com",
  64. id="foo",
  65. rate_limited=False,
  66. sender="@as:example.com",
  67. )
  68. as_requester = create_requester("@user:example.com", app_service=appservice)
  69. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  70. allowed, time_allowed = limiter.can_requester_do_action(
  71. as_requester, _time_now_s=0
  72. )
  73. self.assertTrue(allowed)
  74. self.assertEquals(-1, time_allowed)
  75. allowed, time_allowed = limiter.can_requester_do_action(
  76. as_requester, _time_now_s=5
  77. )
  78. self.assertTrue(allowed)
  79. self.assertEquals(-1, time_allowed)
  80. allowed, time_allowed = limiter.can_requester_do_action(
  81. as_requester, _time_now_s=10
  82. )
  83. self.assertTrue(allowed)
  84. self.assertEquals(-1, time_allowed)
  85. def test_allowed_via_ratelimit(self):
  86. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  87. # Shouldn't raise
  88. limiter.ratelimit(key="test_id", _time_now_s=0)
  89. # Should raise
  90. with self.assertRaises(LimitExceededError) as context:
  91. limiter.ratelimit(key="test_id", _time_now_s=5)
  92. self.assertEqual(context.exception.retry_after_ms, 5000)
  93. # Shouldn't raise
  94. limiter.ratelimit(key="test_id", _time_now_s=10)
  95. def test_allowed_via_can_do_action_and_overriding_parameters(self):
  96. """Test that we can override options of can_do_action that would otherwise fail
  97. an action
  98. """
  99. # Create a Ratelimiter with a very low allowed rate_hz and burst_count
  100. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  101. # First attempt should be allowed
  102. allowed, time_allowed = limiter.can_do_action(
  103. ("test_id",),
  104. _time_now_s=0,
  105. )
  106. self.assertTrue(allowed)
  107. self.assertEqual(10.0, time_allowed)
  108. # Second attempt, 1s later, will fail
  109. allowed, time_allowed = limiter.can_do_action(
  110. ("test_id",),
  111. _time_now_s=1,
  112. )
  113. self.assertFalse(allowed)
  114. self.assertEqual(10.0, time_allowed)
  115. # But, if we allow 10 actions/sec for this request, we should be allowed
  116. # to continue.
  117. allowed, time_allowed = limiter.can_do_action(
  118. ("test_id",), _time_now_s=1, rate_hz=10.0
  119. )
  120. self.assertTrue(allowed)
  121. self.assertEqual(1.1, time_allowed)
  122. # Similarly if we allow a burst of 10 actions
  123. allowed, time_allowed = limiter.can_do_action(
  124. ("test_id",), _time_now_s=1, burst_count=10
  125. )
  126. self.assertTrue(allowed)
  127. self.assertEqual(1.0, time_allowed)
  128. def test_allowed_via_ratelimit_and_overriding_parameters(self):
  129. """Test that we can override options of the ratelimit method that would otherwise
  130. fail an action
  131. """
  132. # Create a Ratelimiter with a very low allowed rate_hz and burst_count
  133. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  134. # First attempt should be allowed
  135. limiter.ratelimit(key=("test_id",), _time_now_s=0)
  136. # Second attempt, 1s later, will fail
  137. with self.assertRaises(LimitExceededError) as context:
  138. limiter.ratelimit(key=("test_id",), _time_now_s=1)
  139. self.assertEqual(context.exception.retry_after_ms, 9000)
  140. # But, if we allow 10 actions/sec for this request, we should be allowed
  141. # to continue.
  142. limiter.ratelimit(key=("test_id",), _time_now_s=1, rate_hz=10.0)
  143. # Similarly if we allow a burst of 10 actions
  144. limiter.ratelimit(key=("test_id",), _time_now_s=1, burst_count=10)
  145. def test_pruning(self):
  146. limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1)
  147. limiter.can_do_action(key="test_id_1", _time_now_s=0)
  148. self.assertIn("test_id_1", limiter.actions)
  149. limiter.can_do_action(key="test_id_2", _time_now_s=10)
  150. self.assertNotIn("test_id_1", limiter.actions)