test_mau.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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 synapse.api.constants import LoginType
  18. from synapse.api.errors import Codes, HttpResponseException, SynapseError
  19. from synapse.appservice import ApplicationService
  20. from synapse.rest.client.v2_alpha import register, sync
  21. from tests import unittest
  22. from tests.unittest import override_config
  23. from tests.utils import default_config
  24. class TestMauLimit(unittest.HomeserverTestCase):
  25. servlets = [register.register_servlets, sync.register_servlets]
  26. def default_config(self):
  27. config = default_config("test")
  28. config.update(
  29. {
  30. "registrations_require_3pid": [],
  31. "limit_usage_by_mau": True,
  32. "max_mau_value": 2,
  33. "mau_trial_days": 0,
  34. "server_notices": {
  35. "system_mxid_localpart": "server",
  36. "room_name": "Test Server Notice Room",
  37. },
  38. }
  39. )
  40. # apply any additional config which was specified via the override_config
  41. # decorator.
  42. if self._extra_config is not None:
  43. config.update(self._extra_config)
  44. return config
  45. def prepare(self, reactor, clock, homeserver):
  46. self.store = homeserver.get_datastore()
  47. def test_simple_deny_mau(self):
  48. # Create and sync so that the MAU counts get updated
  49. token1 = self.create_user("kermit1")
  50. self.do_sync_for_user(token1)
  51. token2 = self.create_user("kermit2")
  52. self.do_sync_for_user(token2)
  53. # check we're testing what we think we are: there should be two active users
  54. self.assertEqual(self.get_success(self.store.get_monthly_active_count()), 2)
  55. # We've created and activated two users, we shouldn't be able to
  56. # register new users
  57. with self.assertRaises(SynapseError) as cm:
  58. self.create_user("kermit3")
  59. e = cm.exception
  60. self.assertEqual(e.code, 403)
  61. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  62. def test_as_ignores_mau(self):
  63. """Test that application services can still create users when the MAU
  64. limit has been reached. This only works when application service
  65. user ip tracking is disabled.
  66. """
  67. # Create and sync so that the MAU counts get updated
  68. token1 = self.create_user("kermit1")
  69. self.do_sync_for_user(token1)
  70. token2 = self.create_user("kermit2")
  71. self.do_sync_for_user(token2)
  72. # check we're testing what we think we are: there should be two active users
  73. self.assertEqual(self.get_success(self.store.get_monthly_active_count()), 2)
  74. # We've created and activated two users, we shouldn't be able to
  75. # register new users
  76. with self.assertRaises(SynapseError) as cm:
  77. self.create_user("kermit3")
  78. e = cm.exception
  79. self.assertEqual(e.code, 403)
  80. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  81. # Cheekily add an application service that we use to register a new user
  82. # with.
  83. as_token = "foobartoken"
  84. self.store.services_cache.append(
  85. ApplicationService(
  86. token=as_token,
  87. hostname=self.hs.hostname,
  88. id="SomeASID",
  89. sender="@as_sender:test",
  90. namespaces={"users": [{"regex": "@as_*", "exclusive": True}]},
  91. )
  92. )
  93. self.create_user("as_kermit4", token=as_token)
  94. def test_allowed_after_a_month_mau(self):
  95. # Create and sync so that the MAU counts get updated
  96. token1 = self.create_user("kermit1")
  97. self.do_sync_for_user(token1)
  98. token2 = self.create_user("kermit2")
  99. self.do_sync_for_user(token2)
  100. # Advance time by 31 days
  101. self.reactor.advance(31 * 24 * 60 * 60)
  102. self.get_success(self.store.reap_monthly_active_users())
  103. self.reactor.advance(0)
  104. # We should be able to register more users
  105. token3 = self.create_user("kermit3")
  106. self.do_sync_for_user(token3)
  107. @override_config({"mau_trial_days": 1})
  108. def test_trial_delay(self):
  109. # We should be able to register more than the limit initially
  110. token1 = self.create_user("kermit1")
  111. self.do_sync_for_user(token1)
  112. token2 = self.create_user("kermit2")
  113. self.do_sync_for_user(token2)
  114. token3 = self.create_user("kermit3")
  115. self.do_sync_for_user(token3)
  116. # Advance time by 2 days
  117. self.reactor.advance(2 * 24 * 60 * 60)
  118. # Two users should be able to sync
  119. self.do_sync_for_user(token1)
  120. self.do_sync_for_user(token2)
  121. # But the third should fail
  122. with self.assertRaises(SynapseError) as cm:
  123. self.do_sync_for_user(token3)
  124. e = cm.exception
  125. self.assertEqual(e.code, 403)
  126. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  127. # And new registrations are now denied too
  128. with self.assertRaises(SynapseError) as cm:
  129. self.create_user("kermit4")
  130. e = cm.exception
  131. self.assertEqual(e.code, 403)
  132. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  133. @override_config({"mau_trial_days": 1})
  134. def test_trial_users_cant_come_back(self):
  135. self.hs.config.mau_trial_days = 1
  136. # We should be able to register more than the limit initially
  137. token1 = self.create_user("kermit1")
  138. self.do_sync_for_user(token1)
  139. token2 = self.create_user("kermit2")
  140. self.do_sync_for_user(token2)
  141. token3 = self.create_user("kermit3")
  142. self.do_sync_for_user(token3)
  143. # Advance time by 2 days
  144. self.reactor.advance(2 * 24 * 60 * 60)
  145. # Two users should be able to sync
  146. self.do_sync_for_user(token1)
  147. self.do_sync_for_user(token2)
  148. # Advance by 2 months so everyone falls out of MAU
  149. self.reactor.advance(60 * 24 * 60 * 60)
  150. self.get_success(self.store.reap_monthly_active_users())
  151. # We can create as many new users as we want
  152. token4 = self.create_user("kermit4")
  153. self.do_sync_for_user(token4)
  154. token5 = self.create_user("kermit5")
  155. self.do_sync_for_user(token5)
  156. token6 = self.create_user("kermit6")
  157. self.do_sync_for_user(token6)
  158. # users 2 and 3 can come back to bring us back up to MAU limit
  159. self.do_sync_for_user(token2)
  160. self.do_sync_for_user(token3)
  161. # New trial users can still sync
  162. self.do_sync_for_user(token4)
  163. self.do_sync_for_user(token5)
  164. self.do_sync_for_user(token6)
  165. # But old user can't
  166. with self.assertRaises(SynapseError) as cm:
  167. self.do_sync_for_user(token1)
  168. e = cm.exception
  169. self.assertEqual(e.code, 403)
  170. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  171. @override_config(
  172. # max_mau_value should not matter
  173. {"max_mau_value": 1, "limit_usage_by_mau": False, "mau_stats_only": True}
  174. )
  175. def test_tracked_but_not_limited(self):
  176. # Simply being able to create 2 users indicates that the
  177. # limit was not reached.
  178. token1 = self.create_user("kermit1")
  179. self.do_sync_for_user(token1)
  180. token2 = self.create_user("kermit2")
  181. self.do_sync_for_user(token2)
  182. # We do want to verify that the number of tracked users
  183. # matches what we want though
  184. count = self.store.get_monthly_active_count()
  185. self.reactor.advance(100)
  186. self.assertEqual(2, self.successResultOf(count))
  187. def create_user(self, localpart, token=None):
  188. request_data = json.dumps(
  189. {
  190. "username": localpart,
  191. "password": "monkey",
  192. "auth": {"type": LoginType.DUMMY},
  193. }
  194. )
  195. channel = self.make_request(
  196. "POST", "/register", request_data, access_token=token,
  197. )
  198. if channel.code != 200:
  199. raise HttpResponseException(
  200. channel.code, channel.result["reason"], channel.result["body"]
  201. ).to_synapse_error()
  202. access_token = channel.json_body["access_token"]
  203. return access_token
  204. def do_sync_for_user(self, token):
  205. channel = self.make_request("GET", "/sync", access_token=token)
  206. if channel.code != 200:
  207. raise HttpResponseException(
  208. channel.code, channel.result["reason"], channel.result["body"]
  209. ).to_synapse_error()