diff --git a/tests/api/test_ratelimiting.py b/tests/api/test_ratelimiting.py
index fa96ba07a5..dcf0110c16 100644
--- a/tests/api/test_ratelimiting.py
+++ b/tests/api/test_ratelimiting.py
@@ -230,3 +230,60 @@ class TestRatelimiter(unittest.HomeserverTestCase):
# Shouldn't raise
for _ in range(20):
self.get_success_or_raise(limiter.ratelimit(requester, _time_now_s=0))
+
+ def test_multiple_actions(self):
+ limiter = Ratelimiter(
+ store=self.hs.get_datastore(), clock=None, rate_hz=0.1, burst_count=3
+ )
+ # Test that 4 actions aren't allowed with a maximum burst of 3.
+ allowed, time_allowed = self.get_success_or_raise(
+ limiter.can_do_action(None, key="test_id", n_actions=4, _time_now_s=0)
+ )
+ self.assertFalse(allowed)
+
+ # Test that 3 actions are allowed with a maximum burst of 3.
+ allowed, time_allowed = self.get_success_or_raise(
+ limiter.can_do_action(None, key="test_id", n_actions=3, _time_now_s=0)
+ )
+ self.assertTrue(allowed)
+ self.assertEquals(10.0, time_allowed)
+
+ # Test that, after doing these 3 actions, we can't do any more action without
+ # waiting.
+ allowed, time_allowed = self.get_success_or_raise(
+ limiter.can_do_action(None, key="test_id", n_actions=1, _time_now_s=0)
+ )
+ self.assertFalse(allowed)
+ self.assertEquals(10.0, time_allowed)
+
+ # Test that after waiting we can do only 1 action.
+ allowed, time_allowed = self.get_success_or_raise(
+ limiter.can_do_action(
+ None,
+ key="test_id",
+ update=False,
+ n_actions=1,
+ _time_now_s=10,
+ )
+ )
+ self.assertTrue(allowed)
+ # The time allowed is the current time because we could still repeat the action
+ # once.
+ self.assertEquals(10.0, time_allowed)
+
+ allowed, time_allowed = self.get_success_or_raise(
+ limiter.can_do_action(None, key="test_id", n_actions=2, _time_now_s=10)
+ )
+ self.assertFalse(allowed)
+ # The time allowed doesn't change despite allowed being False because, while we
+ # don't allow 2 actions, we could still do 1.
+ self.assertEquals(10.0, time_allowed)
+
+ # Test that after waiting a bit more we can do 2 actions.
+ allowed, time_allowed = self.get_success_or_raise(
+ limiter.can_do_action(None, key="test_id", n_actions=2, _time_now_s=20)
+ )
+ self.assertTrue(allowed)
+ # The time allowed is the current time because we could still repeat the action
+ # once.
+ self.assertEquals(20.0, time_allowed)
diff --git a/tests/rest/client/v1/test_rooms.py b/tests/rest/client/v1/test_rooms.py
index a3694f3d02..7c4bdcdfdd 100644
--- a/tests/rest/client/v1/test_rooms.py
+++ b/tests/rest/client/v1/test_rooms.py
@@ -463,6 +463,43 @@ class RoomsCreateTestCase(RoomBase):
)
self.assertEquals(400, channel.code)
+ @unittest.override_config({"rc_invites": {"per_room": {"burst_count": 3}}})
+ def test_post_room_invitees_ratelimit(self):
+ """Test that invites sent when creating a room are ratelimited by a RateLimiter,
+ which ratelimits them correctly, including by not limiting when the requester is
+ exempt from ratelimiting.
+ """
+
+ # Build the request's content. We use local MXIDs because invites over federation
+ # are more difficult to mock.
+ content = json.dumps(
+ {
+ "invite": [
+ "@alice1:red",
+ "@alice2:red",
+ "@alice3:red",
+ "@alice4:red",
+ ]
+ }
+ ).encode("utf8")
+
+ # Test that the invites are correctly ratelimited.
+ channel = self.make_request("POST", "/createRoom", content)
+ self.assertEqual(400, channel.code)
+ self.assertEqual(
+ "Cannot invite so many users at once",
+ channel.json_body["error"],
+ )
+
+ # Add the current user to the ratelimit overrides, allowing them no ratelimiting.
+ self.get_success(
+ self.hs.get_datastore().set_ratelimit_for_user(self.user_id, 0, 0)
+ )
+
+ # Test that the invites aren't ratelimited anymore.
+ channel = self.make_request("POST", "/createRoom", content)
+ self.assertEqual(200, channel.code)
+
class RoomTopicTestCase(RoomBase):
""" Tests /rooms/$room_id/topic REST events. """
|