test_mau.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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. hostname=self.hs.hostname,
  87. id="SomeASID",
  88. sender="@as_sender:test",
  89. namespaces={"users": [{"regex": "@as_*", "exclusive": True}]},
  90. )
  91. )
  92. self.create_user("as_kermit4", token=as_token, appservice=True)
  93. def test_allowed_after_a_month_mau(self):
  94. # Create and sync so that the MAU counts get updated
  95. token1 = self.create_user("kermit1")
  96. self.do_sync_for_user(token1)
  97. token2 = self.create_user("kermit2")
  98. self.do_sync_for_user(token2)
  99. # Advance time by 31 days
  100. self.reactor.advance(31 * 24 * 60 * 60)
  101. self.get_success(self.store.reap_monthly_active_users())
  102. self.reactor.advance(0)
  103. # We should be able to register more users
  104. token3 = self.create_user("kermit3")
  105. self.do_sync_for_user(token3)
  106. @override_config({"mau_trial_days": 1})
  107. def test_trial_delay(self):
  108. # We should be able to register more than the limit initially
  109. token1 = self.create_user("kermit1")
  110. self.do_sync_for_user(token1)
  111. token2 = self.create_user("kermit2")
  112. self.do_sync_for_user(token2)
  113. token3 = self.create_user("kermit3")
  114. self.do_sync_for_user(token3)
  115. # Advance time by 2 days
  116. self.reactor.advance(2 * 24 * 60 * 60)
  117. # Two users should be able to sync
  118. self.do_sync_for_user(token1)
  119. self.do_sync_for_user(token2)
  120. # But the third should fail
  121. with self.assertRaises(SynapseError) as cm:
  122. self.do_sync_for_user(token3)
  123. e = cm.exception
  124. self.assertEqual(e.code, 403)
  125. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  126. # And new registrations are now denied too
  127. with self.assertRaises(SynapseError) as cm:
  128. self.create_user("kermit4")
  129. e = cm.exception
  130. self.assertEqual(e.code, 403)
  131. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  132. @override_config({"mau_trial_days": 1})
  133. def test_trial_users_cant_come_back(self):
  134. self.hs.config.server.mau_trial_days = 1
  135. # We should be able to register more than the limit initially
  136. token1 = self.create_user("kermit1")
  137. self.do_sync_for_user(token1)
  138. token2 = self.create_user("kermit2")
  139. self.do_sync_for_user(token2)
  140. token3 = self.create_user("kermit3")
  141. self.do_sync_for_user(token3)
  142. # Advance time by 2 days
  143. self.reactor.advance(2 * 24 * 60 * 60)
  144. # Two users should be able to sync
  145. self.do_sync_for_user(token1)
  146. self.do_sync_for_user(token2)
  147. # Advance by 2 months so everyone falls out of MAU
  148. self.reactor.advance(60 * 24 * 60 * 60)
  149. self.get_success(self.store.reap_monthly_active_users())
  150. # We can create as many new users as we want
  151. token4 = self.create_user("kermit4")
  152. self.do_sync_for_user(token4)
  153. token5 = self.create_user("kermit5")
  154. self.do_sync_for_user(token5)
  155. token6 = self.create_user("kermit6")
  156. self.do_sync_for_user(token6)
  157. # users 2 and 3 can come back to bring us back up to MAU limit
  158. self.do_sync_for_user(token2)
  159. self.do_sync_for_user(token3)
  160. # New trial users can still sync
  161. self.do_sync_for_user(token4)
  162. self.do_sync_for_user(token5)
  163. self.do_sync_for_user(token6)
  164. # But old user can't
  165. with self.assertRaises(SynapseError) as cm:
  166. self.do_sync_for_user(token1)
  167. e = cm.exception
  168. self.assertEqual(e.code, 403)
  169. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  170. @override_config(
  171. # max_mau_value should not matter
  172. {"max_mau_value": 1, "limit_usage_by_mau": False, "mau_stats_only": True}
  173. )
  174. def test_tracked_but_not_limited(self):
  175. # Simply being able to create 2 users indicates that the
  176. # limit was not reached.
  177. token1 = self.create_user("kermit1")
  178. self.do_sync_for_user(token1)
  179. token2 = self.create_user("kermit2")
  180. self.do_sync_for_user(token2)
  181. # We do want to verify that the number of tracked users
  182. # matches what we want though
  183. count = self.store.get_monthly_active_count()
  184. self.reactor.advance(100)
  185. self.assertEqual(2, self.successResultOf(count))
  186. @override_config(
  187. {
  188. "mau_trial_days": 3,
  189. "mau_appservice_trial_days": {"SomeASID": 1, "AnotherASID": 2},
  190. }
  191. )
  192. def test_as_trial_days(self):
  193. user_tokens: List[str] = []
  194. def advance_time_and_sync():
  195. self.reactor.advance(24 * 60 * 61)
  196. for token in user_tokens:
  197. self.do_sync_for_user(token)
  198. # Cheekily add an application service that we use to register a new user
  199. # with.
  200. as_token_1 = "foobartoken1"
  201. self.store.services_cache.append(
  202. ApplicationService(
  203. token=as_token_1,
  204. hostname=self.hs.hostname,
  205. id="SomeASID",
  206. sender="@as_sender_1:test",
  207. namespaces={"users": [{"regex": "@as_1.*", "exclusive": True}]},
  208. )
  209. )
  210. as_token_2 = "foobartoken2"
  211. self.store.services_cache.append(
  212. ApplicationService(
  213. token=as_token_2,
  214. hostname=self.hs.hostname,
  215. id="AnotherASID",
  216. sender="@as_sender_2:test",
  217. namespaces={"users": [{"regex": "@as_2.*", "exclusive": True}]},
  218. )
  219. )
  220. user_tokens.append(self.create_user("kermit1"))
  221. user_tokens.append(self.create_user("kermit2"))
  222. user_tokens.append(
  223. self.create_user("as_1kermit3", token=as_token_1, appservice=True)
  224. )
  225. user_tokens.append(
  226. self.create_user("as_2kermit4", token=as_token_2, appservice=True)
  227. )
  228. # Advance time by 1 day to include the first appservice
  229. advance_time_and_sync()
  230. self.assertEqual(
  231. self.get_success(self.store.get_monthly_active_count_by_service()),
  232. {"SomeASID": 1},
  233. )
  234. # Advance time by 1 day to include the next appservice
  235. advance_time_and_sync()
  236. self.assertEqual(
  237. self.get_success(self.store.get_monthly_active_count_by_service()),
  238. {"SomeASID": 1, "AnotherASID": 1},
  239. )
  240. # Advance time by 1 day to include the native users
  241. advance_time_and_sync()
  242. self.assertEqual(
  243. self.get_success(self.store.get_monthly_active_count_by_service()),
  244. {
  245. "SomeASID": 1,
  246. "AnotherASID": 1,
  247. "native": 2,
  248. },
  249. )
  250. def create_user(self, localpart, token=None, appservice=False):
  251. request_data = {
  252. "username": localpart,
  253. "password": "monkey",
  254. "auth": {"type": LoginType.DUMMY},
  255. }
  256. if appservice:
  257. request_data["type"] = APP_SERVICE_REGISTRATION_TYPE
  258. channel = self.make_request(
  259. "POST",
  260. "/register",
  261. request_data,
  262. access_token=token,
  263. )
  264. if channel.code != 200:
  265. raise HttpResponseException(
  266. channel.code, channel.result["reason"], channel.result["body"]
  267. ).to_synapse_error()
  268. access_token = channel.json_body["access_token"]
  269. return access_token
  270. def do_sync_for_user(self, token):
  271. channel = self.make_request("GET", "/sync", access_token=token)
  272. if channel.code != 200:
  273. raise HttpResponseException(
  274. channel.code, channel.result["reason"], channel.result["body"]
  275. ).to_synapse_error()