test_mau.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 New Vector Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. """Tests REST events for /rooms paths."""
  16. import json
  17. from mock import Mock, NonCallableMock
  18. from synapse.api.constants import LoginType
  19. from synapse.api.errors import Codes, HttpResponseException, SynapseError
  20. from synapse.http.server import JsonResource
  21. from synapse.rest.client.v2_alpha import register, sync
  22. from synapse.util import Clock
  23. from tests import unittest
  24. from tests.server import (
  25. ThreadedMemoryReactorClock,
  26. make_request,
  27. render,
  28. setup_test_homeserver,
  29. )
  30. class TestMauLimit(unittest.TestCase):
  31. def setUp(self):
  32. self.reactor = ThreadedMemoryReactorClock()
  33. self.clock = Clock(self.reactor)
  34. self.hs = setup_test_homeserver(
  35. self.addCleanup,
  36. "red",
  37. http_client=None,
  38. clock=self.clock,
  39. reactor=self.reactor,
  40. federation_client=Mock(),
  41. ratelimiter=NonCallableMock(spec_set=["send_message"]),
  42. )
  43. self.store = self.hs.get_datastore()
  44. self.hs.config.registrations_require_3pid = []
  45. self.hs.config.enable_registration_captcha = False
  46. self.hs.config.recaptcha_public_key = []
  47. self.hs.config.limit_usage_by_mau = True
  48. self.hs.config.hs_disabled = False
  49. self.hs.config.max_mau_value = 2
  50. self.hs.config.mau_trial_days = 0
  51. self.hs.config.server_notices_mxid = "@server:red"
  52. self.hs.config.server_notices_mxid_display_name = None
  53. self.hs.config.server_notices_mxid_avatar_url = None
  54. self.hs.config.server_notices_room_name = "Test Server Notice Room"
  55. self.resource = JsonResource(self.hs)
  56. register.register_servlets(self.hs, self.resource)
  57. sync.register_servlets(self.hs, self.resource)
  58. def test_simple_deny_mau(self):
  59. # Create and sync so that the MAU counts get updated
  60. token1 = self.create_user("kermit1")
  61. self.do_sync_for_user(token1)
  62. token2 = self.create_user("kermit2")
  63. self.do_sync_for_user(token2)
  64. # We've created and activated two users, we shouldn't be able to
  65. # register new users
  66. with self.assertRaises(SynapseError) as cm:
  67. self.create_user("kermit3")
  68. e = cm.exception
  69. self.assertEqual(e.code, 403)
  70. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  71. def test_allowed_after_a_month_mau(self):
  72. # Create and sync so that the MAU counts get updated
  73. token1 = self.create_user("kermit1")
  74. self.do_sync_for_user(token1)
  75. token2 = self.create_user("kermit2")
  76. self.do_sync_for_user(token2)
  77. # Advance time by 31 days
  78. self.reactor.advance(31 * 24 * 60 * 60)
  79. self.store.reap_monthly_active_users()
  80. self.reactor.advance(0)
  81. # We should be able to register more users
  82. token3 = self.create_user("kermit3")
  83. self.do_sync_for_user(token3)
  84. def test_trial_delay(self):
  85. self.hs.config.mau_trial_days = 1
  86. # We should be able to register more than the limit initially
  87. token1 = self.create_user("kermit1")
  88. self.do_sync_for_user(token1)
  89. token2 = self.create_user("kermit2")
  90. self.do_sync_for_user(token2)
  91. token3 = self.create_user("kermit3")
  92. self.do_sync_for_user(token3)
  93. # Advance time by 2 days
  94. self.reactor.advance(2 * 24 * 60 * 60)
  95. # Two users should be able to sync
  96. self.do_sync_for_user(token1)
  97. self.do_sync_for_user(token2)
  98. # But the third should fail
  99. with self.assertRaises(SynapseError) as cm:
  100. self.do_sync_for_user(token3)
  101. e = cm.exception
  102. self.assertEqual(e.code, 403)
  103. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  104. # And new registrations are now denied too
  105. with self.assertRaises(SynapseError) as cm:
  106. self.create_user("kermit4")
  107. e = cm.exception
  108. self.assertEqual(e.code, 403)
  109. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  110. def test_trial_users_cant_come_back(self):
  111. self.hs.config.mau_trial_days = 1
  112. # We should be able to register more than the limit initially
  113. token1 = self.create_user("kermit1")
  114. self.do_sync_for_user(token1)
  115. token2 = self.create_user("kermit2")
  116. self.do_sync_for_user(token2)
  117. token3 = self.create_user("kermit3")
  118. self.do_sync_for_user(token3)
  119. # Advance time by 2 days
  120. self.reactor.advance(2 * 24 * 60 * 60)
  121. # Two users should be able to sync
  122. self.do_sync_for_user(token1)
  123. self.do_sync_for_user(token2)
  124. # Advance by 2 months so everyone falls out of MAU
  125. self.reactor.advance(60 * 24 * 60 * 60)
  126. self.store.reap_monthly_active_users()
  127. self.reactor.advance(0)
  128. # We can create as many new users as we want
  129. token4 = self.create_user("kermit4")
  130. self.do_sync_for_user(token4)
  131. token5 = self.create_user("kermit5")
  132. self.do_sync_for_user(token5)
  133. token6 = self.create_user("kermit6")
  134. self.do_sync_for_user(token6)
  135. # users 2 and 3 can come back to bring us back up to MAU limit
  136. self.do_sync_for_user(token2)
  137. self.do_sync_for_user(token3)
  138. # New trial users can still sync
  139. self.do_sync_for_user(token4)
  140. self.do_sync_for_user(token5)
  141. self.do_sync_for_user(token6)
  142. # But old user cant
  143. with self.assertRaises(SynapseError) as cm:
  144. self.do_sync_for_user(token1)
  145. e = cm.exception
  146. self.assertEqual(e.code, 403)
  147. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  148. def create_user(self, localpart):
  149. request_data = json.dumps(
  150. {
  151. "username": localpart,
  152. "password": "monkey",
  153. "auth": {"type": LoginType.DUMMY},
  154. }
  155. )
  156. request, channel = make_request("POST", "/register", request_data)
  157. render(request, self.resource, self.reactor)
  158. if channel.code != 200:
  159. raise HttpResponseException(
  160. channel.code, channel.result["reason"], channel.result["body"]
  161. ).to_synapse_error()
  162. access_token = channel.json_body["access_token"]
  163. return access_token
  164. def do_sync_for_user(self, token):
  165. request, channel = make_request(
  166. "GET", "/sync", access_token=token.encode('ascii')
  167. )
  168. render(request, self.resource, self.reactor)
  169. if channel.code != 200:
  170. raise HttpResponseException(
  171. channel.code, channel.result["reason"], channel.result["body"]
  172. ).to_synapse_error()