test_mau.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. # Copyright 2018 New Vector Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Tests REST events for /rooms paths."""
  15. from typing import List
  16. from synapse.api.constants import APP_SERVICE_REGISTRATION_TYPE, LoginType
  17. from synapse.api.errors import Codes, HttpResponseException, SynapseError
  18. from synapse.appservice import ApplicationService
  19. from synapse.rest.client import register, sync
  20. from tests import unittest
  21. from tests.unittest import override_config
  22. from tests.utils import default_config
  23. class TestMauLimit(unittest.HomeserverTestCase):
  24. servlets = [register.register_servlets, sync.register_servlets]
  25. def default_config(self):
  26. config = default_config("test")
  27. config.update(
  28. {
  29. "registrations_require_3pid": [],
  30. "limit_usage_by_mau": True,
  31. "max_mau_value": 2,
  32. "mau_trial_days": 0,
  33. "server_notices": {
  34. "system_mxid_localpart": "server",
  35. "room_name": "Test Server Notice Room",
  36. },
  37. }
  38. )
  39. # apply any additional config which was specified via the override_config
  40. # decorator.
  41. if self._extra_config is not None:
  42. config.update(self._extra_config)
  43. return config
  44. def prepare(self, reactor, clock, homeserver):
  45. self.store = homeserver.get_datastores().main
  46. def test_simple_deny_mau(self):
  47. # Create and sync so that the MAU counts get updated
  48. token1 = self.create_user("kermit1")
  49. self.do_sync_for_user(token1)
  50. token2 = self.create_user("kermit2")
  51. self.do_sync_for_user(token2)
  52. # check we're testing what we think we are: there should be two active users
  53. self.assertEqual(self.get_success(self.store.get_monthly_active_count()), 2)
  54. # We've created and activated two users, we shouldn't be able to
  55. # register new users
  56. with self.assertRaises(SynapseError) as cm:
  57. self.create_user("kermit3")
  58. e = cm.exception
  59. self.assertEqual(e.code, 403)
  60. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  61. def test_as_ignores_mau(self):
  62. """Test that application services can still create users when the MAU
  63. limit has been reached. This only works when application service
  64. user ip tracking is disabled.
  65. """
  66. # Create and sync so that the MAU counts get updated
  67. token1 = self.create_user("kermit1")
  68. self.do_sync_for_user(token1)
  69. token2 = self.create_user("kermit2")
  70. self.do_sync_for_user(token2)
  71. # check we're testing what we think we are: there should be two active users
  72. self.assertEqual(self.get_success(self.store.get_monthly_active_count()), 2)
  73. # We've created and activated two users, we shouldn't be able to
  74. # register new users
  75. with self.assertRaises(SynapseError) as cm:
  76. self.create_user("kermit3")
  77. e = cm.exception
  78. self.assertEqual(e.code, 403)
  79. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  80. # Cheekily add an application service that we use to register a new user
  81. # with.
  82. as_token = "foobartoken"
  83. self.store.services_cache.append(
  84. ApplicationService(
  85. token=as_token,
  86. id="SomeASID",
  87. sender="@as_sender:test",
  88. namespaces={"users": [{"regex": "@as_*", "exclusive": True}]},
  89. )
  90. )
  91. self.create_user("as_kermit4", token=as_token, appservice=True)
  92. def test_allowed_after_a_month_mau(self):
  93. # Create and sync so that the MAU counts get updated
  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. # Advance time by 31 days
  99. self.reactor.advance(31 * 24 * 60 * 60)
  100. self.get_success(self.store.reap_monthly_active_users())
  101. self.reactor.advance(0)
  102. # We should be able to register more users
  103. token3 = self.create_user("kermit3")
  104. self.do_sync_for_user(token3)
  105. @override_config({"mau_trial_days": 1})
  106. def test_trial_delay(self):
  107. # We should be able to register more than the limit initially
  108. token1 = self.create_user("kermit1")
  109. self.do_sync_for_user(token1)
  110. token2 = self.create_user("kermit2")
  111. self.do_sync_for_user(token2)
  112. token3 = self.create_user("kermit3")
  113. self.do_sync_for_user(token3)
  114. # Advance time by 2 days
  115. self.reactor.advance(2 * 24 * 60 * 60)
  116. # Two users should be able to sync
  117. self.do_sync_for_user(token1)
  118. self.do_sync_for_user(token2)
  119. # But the third should fail
  120. with self.assertRaises(SynapseError) as cm:
  121. self.do_sync_for_user(token3)
  122. e = cm.exception
  123. self.assertEqual(e.code, 403)
  124. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  125. # And new registrations are now denied too
  126. with self.assertRaises(SynapseError) as cm:
  127. self.create_user("kermit4")
  128. e = cm.exception
  129. self.assertEqual(e.code, 403)
  130. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  131. @override_config({"mau_trial_days": 1})
  132. def test_trial_users_cant_come_back(self):
  133. self.hs.config.server.mau_trial_days = 1
  134. # We should be able to register more than the limit initially
  135. token1 = self.create_user("kermit1")
  136. self.do_sync_for_user(token1)
  137. token2 = self.create_user("kermit2")
  138. self.do_sync_for_user(token2)
  139. token3 = self.create_user("kermit3")
  140. self.do_sync_for_user(token3)
  141. # Advance time by 2 days
  142. self.reactor.advance(2 * 24 * 60 * 60)
  143. # Two users should be able to sync
  144. self.do_sync_for_user(token1)
  145. self.do_sync_for_user(token2)
  146. # Advance by 2 months so everyone falls out of MAU
  147. self.reactor.advance(60 * 24 * 60 * 60)
  148. self.get_success(self.store.reap_monthly_active_users())
  149. # We can create as many new users as we want
  150. token4 = self.create_user("kermit4")
  151. self.do_sync_for_user(token4)
  152. token5 = self.create_user("kermit5")
  153. self.do_sync_for_user(token5)
  154. token6 = self.create_user("kermit6")
  155. self.do_sync_for_user(token6)
  156. # users 2 and 3 can come back to bring us back up to MAU limit
  157. self.do_sync_for_user(token2)
  158. self.do_sync_for_user(token3)
  159. # New trial users can still sync
  160. self.do_sync_for_user(token4)
  161. self.do_sync_for_user(token5)
  162. self.do_sync_for_user(token6)
  163. # But old user can't
  164. with self.assertRaises(SynapseError) as cm:
  165. self.do_sync_for_user(token1)
  166. e = cm.exception
  167. self.assertEqual(e.code, 403)
  168. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  169. @override_config(
  170. # max_mau_value should not matter
  171. {"max_mau_value": 1, "limit_usage_by_mau": False, "mau_stats_only": True}
  172. )
  173. def test_tracked_but_not_limited(self):
  174. # Simply being able to create 2 users indicates that the
  175. # limit was not reached.
  176. token1 = self.create_user("kermit1")
  177. self.do_sync_for_user(token1)
  178. token2 = self.create_user("kermit2")
  179. self.do_sync_for_user(token2)
  180. # We do want to verify that the number of tracked users
  181. # matches what we want though
  182. count = self.store.get_monthly_active_count()
  183. self.reactor.advance(100)
  184. self.assertEqual(2, self.successResultOf(count))
  185. @override_config(
  186. {
  187. "mau_trial_days": 3,
  188. "mau_appservice_trial_days": {"SomeASID": 1, "AnotherASID": 2},
  189. }
  190. )
  191. def test_as_trial_days(self):
  192. user_tokens: List[str] = []
  193. def advance_time_and_sync():
  194. self.reactor.advance(24 * 60 * 61)
  195. for token in user_tokens:
  196. self.do_sync_for_user(token)
  197. # Cheekily add an application service that we use to register a new user
  198. # with.
  199. as_token_1 = "foobartoken1"
  200. self.store.services_cache.append(
  201. ApplicationService(
  202. token=as_token_1,
  203. id="SomeASID",
  204. sender="@as_sender_1:test",
  205. namespaces={"users": [{"regex": "@as_1.*", "exclusive": True}]},
  206. )
  207. )
  208. as_token_2 = "foobartoken2"
  209. self.store.services_cache.append(
  210. ApplicationService(
  211. token=as_token_2,
  212. id="AnotherASID",
  213. sender="@as_sender_2:test",
  214. namespaces={"users": [{"regex": "@as_2.*", "exclusive": True}]},
  215. )
  216. )
  217. user_tokens.append(self.create_user("kermit1"))
  218. user_tokens.append(self.create_user("kermit2"))
  219. user_tokens.append(
  220. self.create_user("as_1kermit3", token=as_token_1, appservice=True)
  221. )
  222. user_tokens.append(
  223. self.create_user("as_2kermit4", token=as_token_2, appservice=True)
  224. )
  225. # Advance time by 1 day to include the first appservice
  226. advance_time_and_sync()
  227. self.assertEqual(
  228. self.get_success(self.store.get_monthly_active_count_by_service()),
  229. {"SomeASID": 1},
  230. )
  231. # Advance time by 1 day to include the next appservice
  232. advance_time_and_sync()
  233. self.assertEqual(
  234. self.get_success(self.store.get_monthly_active_count_by_service()),
  235. {"SomeASID": 1, "AnotherASID": 1},
  236. )
  237. # Advance time by 1 day to include the native users
  238. advance_time_and_sync()
  239. self.assertEqual(
  240. self.get_success(self.store.get_monthly_active_count_by_service()),
  241. {
  242. "SomeASID": 1,
  243. "AnotherASID": 1,
  244. "native": 2,
  245. },
  246. )
  247. def create_user(self, localpart, token=None, appservice=False):
  248. request_data = {
  249. "username": localpart,
  250. "password": "monkey",
  251. "auth": {"type": LoginType.DUMMY},
  252. }
  253. if appservice:
  254. request_data["type"] = APP_SERVICE_REGISTRATION_TYPE
  255. channel = self.make_request(
  256. "POST",
  257. "/register",
  258. request_data,
  259. access_token=token,
  260. )
  261. if channel.code != 200:
  262. raise HttpResponseException(
  263. channel.code, channel.result["reason"], channel.result["body"]
  264. ).to_synapse_error()
  265. access_token = channel.json_body["access_token"]
  266. return access_token
  267. def do_sync_for_user(self, token):
  268. channel = self.make_request("GET", "/sync", access_token=token)
  269. if channel.code != 200:
  270. raise HttpResponseException(
  271. channel.code, channel.result["reason"], channel.result["body"]
  272. ).to_synapse_error()