test_mau.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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. import logging
  18. from mock import Mock, NonCallableMock
  19. from synapse.api.constants import LoginType
  20. from synapse.api.errors import Codes, HttpResponseException, SynapseError
  21. from synapse.http.server import JsonResource
  22. from synapse.rest.client.v2_alpha import register, sync
  23. from synapse.util import Clock
  24. from tests import unittest
  25. from tests.server import (
  26. ThreadedMemoryReactorClock,
  27. make_request,
  28. render,
  29. setup_test_homeserver,
  30. )
  31. logger = logging.getLogger(__name__)
  32. ONE_HOUR = 60 * 60 * 1000
  33. class TestMauLimit(unittest.TestCase):
  34. def setUp(self):
  35. self.reactor = ThreadedMemoryReactorClock()
  36. self.clock = Clock(self.reactor)
  37. self.hs = setup_test_homeserver(
  38. self.addCleanup,
  39. "red",
  40. http_client=None,
  41. clock=self.clock,
  42. reactor=self.reactor,
  43. federation_client=Mock(),
  44. ratelimiter=NonCallableMock(spec_set=["send_message"]),
  45. )
  46. self.store = self.hs.get_datastore()
  47. self.hs.config.registrations_require_3pid = []
  48. self.hs.config.enable_registration_captcha = False
  49. self.hs.config.recaptcha_public_key = []
  50. self.hs.config.limit_usage_by_mau = True
  51. self.hs.config.hs_disabled = False
  52. self.hs.config.max_mau_value = 2
  53. self.hs.config.mau_trial_days = 0
  54. self.hs.config.server_notices_mxid = "@server:red"
  55. self.hs.config.server_notices_mxid_display_name = None
  56. self.hs.config.server_notices_mxid_avatar_url = None
  57. self.hs.config.server_notices_room_name = "Test Server Notice Room"
  58. self.resource = JsonResource(self.hs)
  59. register.register_servlets(self.hs, self.resource)
  60. sync.register_servlets(self.hs, self.resource)
  61. def test_simple_deny_mau(self):
  62. # Create and sync so that the MAU counts get updated
  63. token1 = self.create_user("kermit1")
  64. logger.debug("create kermit1 token is %s" % token1)
  65. self.do_sync_for_user(token1)
  66. token2 = self.create_user("kermit2")
  67. self.do_sync_for_user(token2)
  68. # Because adding to
  69. self.reactor.advance(ONE_HOUR)
  70. # We've created and activated two users, we shouldn't be able to
  71. # register new users
  72. with self.assertRaises(SynapseError) as cm:
  73. self.create_user("kermit3")
  74. e = cm.exception
  75. self.assertEqual(e.code, 403)
  76. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  77. def test_allowed_after_a_month_mau(self):
  78. # Create and sync so that the MAU counts get updated
  79. token1 = self.create_user("kermit1")
  80. self.do_sync_for_user(token1)
  81. token2 = self.create_user("kermit2")
  82. self.do_sync_for_user(token2)
  83. # Advance time by 31 days
  84. self.reactor.advance(31 * 24 * 60 * 60)
  85. self.store.reap_monthly_active_users()
  86. self.reactor.advance(0)
  87. # We should be able to register more users
  88. token3 = self.create_user("kermit3")
  89. self.do_sync_for_user(token3)
  90. @unittest.DEBUG
  91. def test_trial_delay(self):
  92. self.hs.config.mau_trial_days = 1
  93. # We should be able to register more than the limit initially
  94. token1 = self.create_user("kermit1")
  95. self.do_sync_for_user(token1)
  96. token2 = self.create_user("kermit2")
  97. self.do_sync_for_user(token2)
  98. token3 = self.create_user("kermit3")
  99. self.do_sync_for_user(token3)
  100. # Advance time by 2 days
  101. self.reactor.advance(2 * 24 * 60 * 60)
  102. # Two users should be able to sync
  103. self.do_sync_for_user(token1)
  104. self.do_sync_for_user(token2)
  105. self.reactor.advance(ONE_HOUR)
  106. # But the third should fail
  107. with self.assertRaises(SynapseError) as cm:
  108. self.do_sync_for_user(token3)
  109. e = cm.exception
  110. self.assertEqual(e.code, 403)
  111. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  112. # And new registrations are now denied too
  113. with self.assertRaises(SynapseError) as cm:
  114. self.create_user("kermit4")
  115. e = cm.exception
  116. self.assertEqual(e.code, 403)
  117. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  118. def test_trial_users_cant_come_back(self):
  119. self.hs.config.mau_trial_days = 1
  120. # We should be able to register more than the limit initially
  121. token1 = self.create_user("kermit1")
  122. self.do_sync_for_user(token1)
  123. token2 = self.create_user("kermit2")
  124. self.do_sync_for_user(token2)
  125. token3 = self.create_user("kermit3")
  126. self.do_sync_for_user(token3)
  127. # Advance time by 2 days
  128. self.reactor.advance(2 * 24 * 60 * 60)
  129. # Two users should be able to sync
  130. self.do_sync_for_user(token1)
  131. self.do_sync_for_user(token2)
  132. # Advance by 2 months so everyone falls out of MAU
  133. self.reactor.advance(60 * 24 * 60 * 60)
  134. self.store.reap_monthly_active_users()
  135. self.reactor.advance(0)
  136. # We can create as many new users as we want
  137. token4 = self.create_user("kermit4")
  138. self.do_sync_for_user(token4)
  139. token5 = self.create_user("kermit5")
  140. self.do_sync_for_user(token5)
  141. token6 = self.create_user("kermit6")
  142. self.do_sync_for_user(token6)
  143. # users 2 and 3 can come back to bring us back up to MAU limit
  144. self.do_sync_for_user(token2)
  145. self.do_sync_for_user(token3)
  146. # New trial users can still sync
  147. self.do_sync_for_user(token4)
  148. self.do_sync_for_user(token5)
  149. self.do_sync_for_user(token6)
  150. # But old user cant
  151. with self.assertRaises(SynapseError) as cm:
  152. self.do_sync_for_user(token1)
  153. e = cm.exception
  154. self.assertEqual(e.code, 403)
  155. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  156. def create_user(self, localpart):
  157. request_data = json.dumps(
  158. {
  159. "username": localpart,
  160. "password": "monkey",
  161. "auth": {"type": LoginType.DUMMY},
  162. }
  163. )
  164. request, channel = make_request("POST", "/register", request_data)
  165. render(request, self.resource, self.reactor)
  166. if channel.code != 200:
  167. raise HttpResponseException(
  168. channel.code, channel.result["reason"], channel.result["body"]
  169. ).to_synapse_error()
  170. access_token = channel.json_body["access_token"]
  171. return access_token
  172. def do_sync_for_user(self, token):
  173. request, channel = make_request(
  174. "GET", "/sync", access_token=token.encode('ascii')
  175. )
  176. render(request, self.resource, self.reactor)
  177. if channel.code != 200:
  178. raise HttpResponseException(
  179. channel.code, channel.result["reason"], channel.result["body"]
  180. ).to_synapse_error()