Optimise some references to hs.config (#7546)

These are surprisingly expensive, and we only really need to do them at startup.
This commit is contained in:
Richard van der Hoff 2020-05-22 21:47:07 +01:00 committed by GitHub
parent 2901f54359
commit f4269694ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 162 additions and 136 deletions

1
changelog.d/7546.misc Normal file
View File

@ -0,0 +1 @@
Optimise some references to `hs.config`.

View File

@ -366,7 +366,9 @@ class EventCreationHandler(object):
self.notifier = hs.get_notifier() self.notifier = hs.get_notifier()
self.config = hs.config self.config = hs.config
self.require_membership_for_aliases = hs.config.require_membership_for_aliases self.require_membership_for_aliases = hs.config.require_membership_for_aliases
self._instance_name = hs.get_instance_name() self._is_event_writer = (
self.config.worker.writers.events == hs.get_instance_name()
)
self.room_invite_state_types = self.hs.config.room_invite_state_types self.room_invite_state_types = self.hs.config.room_invite_state_types
@ -836,7 +838,7 @@ class EventCreationHandler(object):
success = False success = False
try: try:
# If we're a worker we need to hit out to the master. # If we're a worker we need to hit out to the master.
if self.config.worker.writers.events != self._instance_name: if not self._is_event_writer:
result = await self.send_event( result = await self.send_event(
instance_name=self.config.worker.writers.events, instance_name=self.config.worker.writers.events,
event_id=event.event_id, event_id=event.event_id,
@ -906,7 +908,7 @@ class EventCreationHandler(object):
This should only be run on the instance in charge of persisting events. This should only be run on the instance in charge of persisting events.
""" """
assert self.config.worker.writers.events == self._instance_name assert self._is_event_writer
if ratelimit: if ratelimit:
# We check if this is a room admin redacting an event so that we # We check if this is a room admin redacting an event so that we

View File

@ -48,6 +48,12 @@ class ResourceLimitsServerNotices(object):
self._notifier = hs.get_notifier() self._notifier = hs.get_notifier()
self._enabled = (
hs.config.limit_usage_by_mau
and self._server_notices_manager.is_enabled()
and not hs.config.hs_disabled
)
async def maybe_send_server_notice_to_user(self, user_id): async def maybe_send_server_notice_to_user(self, user_id):
"""Check if we need to send a notice to this user, this will be true in """Check if we need to send a notice to this user, this will be true in
two cases. two cases.
@ -61,14 +67,7 @@ class ResourceLimitsServerNotices(object):
Returns: Returns:
Deferred Deferred
""" """
if self._config.hs_disabled is True: if not self._enabled:
return
if self._config.limit_usage_by_mau is False:
return
if not self._server_notices_manager.is_enabled():
# Don't try and send server notices unless they've been enabled
return return
timestamp = await self._store.user_last_seen_monthly_active(user_id) timestamp = await self._store.user_last_seen_monthly_active(user_id)

View File

@ -122,6 +122,10 @@ class MonthlyActiveUsersStore(MonthlyActiveUsersWorkerStore):
def __init__(self, database: Database, db_conn, hs): def __init__(self, database: Database, db_conn, hs):
super(MonthlyActiveUsersStore, self).__init__(database, db_conn, hs) super(MonthlyActiveUsersStore, self).__init__(database, db_conn, hs)
self._limit_usage_by_mau = hs.config.limit_usage_by_mau
self._mau_stats_only = hs.config.mau_stats_only
self._max_mau_value = hs.config.max_mau_value
# Do not add more reserved users than the total allowable number # Do not add more reserved users than the total allowable number
# cur = LoggingTransaction( # cur = LoggingTransaction(
self.db.new_transaction( self.db.new_transaction(
@ -130,7 +134,7 @@ class MonthlyActiveUsersStore(MonthlyActiveUsersWorkerStore):
[], [],
[], [],
self._initialise_reserved_users, self._initialise_reserved_users,
hs.config.mau_limits_reserved_threepids[: self.hs.config.max_mau_value], hs.config.mau_limits_reserved_threepids[: self._max_mau_value],
) )
def _initialise_reserved_users(self, txn, threepids): def _initialise_reserved_users(self, txn, threepids):
@ -142,6 +146,15 @@ class MonthlyActiveUsersStore(MonthlyActiveUsersWorkerStore):
threepids (list[dict]): List of threepid dicts to reserve threepids (list[dict]): List of threepid dicts to reserve
""" """
# XXX what is this function trying to achieve? It upserts into
# monthly_active_users for each *registered* reserved mau user, but why?
#
# - shouldn't there already be an entry for each reserved user (at least
# if they have been active recently)?
#
# - if it's important that the timestamp is kept up to date, why do we only
# run this at startup?
for tp in threepids: for tp in threepids:
user_id = self.get_user_id_by_threepid_txn(txn, tp["medium"], tp["address"]) user_id = self.get_user_id_by_threepid_txn(txn, tp["medium"], tp["address"])
@ -191,8 +204,7 @@ class MonthlyActiveUsersStore(MonthlyActiveUsersWorkerStore):
txn.execute(sql, query_args) txn.execute(sql, query_args)
max_mau_value = self.hs.config.max_mau_value if self._limit_usage_by_mau:
if self.hs.config.limit_usage_by_mau:
# If MAU user count still exceeds the MAU threshold, then delete on # If MAU user count still exceeds the MAU threshold, then delete on
# a least recently active basis. # a least recently active basis.
# Note it is not possible to write this query using OFFSET due to # Note it is not possible to write this query using OFFSET due to
@ -210,13 +222,13 @@ class MonthlyActiveUsersStore(MonthlyActiveUsersWorkerStore):
LIMIT ? LIMIT ?
) )
""" """
txn.execute(sql, (max_mau_value,)) txn.execute(sql, ((self._max_mau_value),))
# Need if/else since 'AND user_id NOT IN ({})' fails on Postgres # Need if/else since 'AND user_id NOT IN ({})' fails on Postgres
# when len(reserved_users) == 0. Works fine on sqlite. # when len(reserved_users) == 0. Works fine on sqlite.
else: else:
# Must be >= 0 for postgres # Must be >= 0 for postgres
num_of_non_reserved_users_to_remove = max( num_of_non_reserved_users_to_remove = max(
max_mau_value - len(reserved_users), 0 self._max_mau_value - len(reserved_users), 0
) )
# It is important to filter reserved users twice to guard # It is important to filter reserved users twice to guard
@ -335,7 +347,7 @@ class MonthlyActiveUsersStore(MonthlyActiveUsersWorkerStore):
Args: Args:
user_id(str): the user_id to query user_id(str): the user_id to query
""" """
if self.hs.config.limit_usage_by_mau or self.hs.config.mau_stats_only: if self._limit_usage_by_mau or self._mau_stats_only:
# Trial users and guests should not be included as part of MAU group # Trial users and guests should not be included as part of MAU group
is_guest = yield self.is_guest(user_id) is_guest = yield self.is_guest(user_id)
if is_guest: if is_guest:
@ -356,11 +368,11 @@ class MonthlyActiveUsersStore(MonthlyActiveUsersWorkerStore):
# In the case where mau_stats_only is True and limit_usage_by_mau is # In the case where mau_stats_only is True and limit_usage_by_mau is
# False, there is no point in checking get_monthly_active_count - it # False, there is no point in checking get_monthly_active_count - it
# adds no value and will break the logic if max_mau_value is exceeded. # adds no value and will break the logic if max_mau_value is exceeded.
if not self.hs.config.limit_usage_by_mau: if not self._limit_usage_by_mau:
yield self.upsert_monthly_active_user(user_id) yield self.upsert_monthly_active_user(user_id)
else: else:
count = yield self.get_monthly_active_count() count = yield self.get_monthly_active_count()
if count < self.hs.config.max_mau_value: if count < self._max_mau_value:
yield self.upsert_monthly_active_user(user_id) yield self.upsert_monthly_active_user(user_id)
elif now - last_seen_timestamp > LAST_SEEN_GRANULARITY: elif now - last_seen_timestamp > LAST_SEEN_GRANULARITY:
yield self.upsert_monthly_active_user(user_id) yield self.upsert_monthly_active_user(user_id)

View File

@ -27,20 +27,33 @@ from synapse.server_notices.resource_limits_server_notices import (
) )
from tests import unittest from tests import unittest
from tests.unittest import override_config
from tests.utils import default_config
class TestResourceLimitsServerNotices(unittest.HomeserverTestCase): class TestResourceLimitsServerNotices(unittest.HomeserverTestCase):
def make_homeserver(self, reactor, clock): def default_config(self):
hs_config = self.default_config() config = default_config("test")
hs_config["server_notices"] = {
config.update(
{
"admin_contact": "mailto:user@test.com",
"limit_usage_by_mau": True,
"server_notices": {
"system_mxid_localpart": "server", "system_mxid_localpart": "server",
"system_mxid_display_name": "test display name", "system_mxid_display_name": "test display name",
"system_mxid_avatar_url": None, "system_mxid_avatar_url": None,
"room_name": "Server Notices", "room_name": "Server Notices",
},
} }
)
hs = self.setup_test_homeserver(config=hs_config) # apply any additional config which was specified via the override_config
return hs # decorator.
if self._extra_config is not None:
config.update(self._extra_config)
return config
def prepare(self, reactor, clock, hs): def prepare(self, reactor, clock, hs):
self.server_notices_sender = self.hs.get_server_notices_sender() self.server_notices_sender = self.hs.get_server_notices_sender()
@ -60,7 +73,6 @@ class TestResourceLimitsServerNotices(unittest.HomeserverTestCase):
) )
self._send_notice = self._rlsn._server_notices_manager.send_notice self._send_notice = self._rlsn._server_notices_manager.send_notice
self.hs.config.limit_usage_by_mau = True
self.user_id = "@user_id:test" self.user_id = "@user_id:test"
self._rlsn._server_notices_manager.get_or_create_notice_room_for_user = Mock( self._rlsn._server_notices_manager.get_or_create_notice_room_for_user = Mock(
@ -68,21 +80,17 @@ class TestResourceLimitsServerNotices(unittest.HomeserverTestCase):
) )
self._rlsn._store.add_tag_to_room = Mock(return_value=defer.succeed(None)) self._rlsn._store.add_tag_to_room = Mock(return_value=defer.succeed(None))
self._rlsn._store.get_tags_for_room = Mock(return_value=defer.succeed({})) self._rlsn._store.get_tags_for_room = Mock(return_value=defer.succeed({}))
self.hs.config.admin_contact = "mailto:user@test.com"
def test_maybe_send_server_notice_to_user_flag_off(self):
"""Tests cases where the flags indicate nothing to do"""
# test hs disabled case
self.hs.config.hs_disabled = True
@override_config({"hs_disabled": True})
def test_maybe_send_server_notice_disabled_hs(self):
"""If the HS is disabled, we should not send notices"""
self.get_success(self._rlsn.maybe_send_server_notice_to_user(self.user_id)) self.get_success(self._rlsn.maybe_send_server_notice_to_user(self.user_id))
self._send_notice.assert_not_called() self._send_notice.assert_not_called()
# Test when mau limiting disabled
self.hs.config.hs_disabled = False
self.hs.config.limit_usage_by_mau = False
self.get_success(self._rlsn.maybe_send_server_notice_to_user(self.user_id))
@override_config({"limit_usage_by_mau": False})
def test_maybe_send_server_notice_to_user_flag_off(self):
"""If mau limiting is disabled, we should not send notices"""
self.get_success(self._rlsn.maybe_send_server_notice_to_user(self.user_id))
self._send_notice.assert_not_called() self._send_notice.assert_not_called()
def test_maybe_send_server_notice_to_user_remove_blocked_notice(self): def test_maybe_send_server_notice_to_user_remove_blocked_notice(self):
@ -153,13 +161,12 @@ class TestResourceLimitsServerNotices(unittest.HomeserverTestCase):
self._send_notice.assert_not_called() self._send_notice.assert_not_called()
@override_config({"mau_limit_alerting": False})
def test_maybe_send_server_notice_when_alerting_suppressed_room_unblocked(self): def test_maybe_send_server_notice_when_alerting_suppressed_room_unblocked(self):
""" """
Test that when server is over MAU limit and alerting is suppressed, then Test that when server is over MAU limit and alerting is suppressed, then
an alert message is not sent into the room an alert message is not sent into the room
""" """
self.hs.config.mau_limit_alerting = False
self._rlsn._auth.check_auth_blocking = Mock( self._rlsn._auth.check_auth_blocking = Mock(
return_value=defer.succeed(None), return_value=defer.succeed(None),
side_effect=ResourceLimitError( side_effect=ResourceLimitError(
@ -170,12 +177,11 @@ class TestResourceLimitsServerNotices(unittest.HomeserverTestCase):
self.assertEqual(self._send_notice.call_count, 0) self.assertEqual(self._send_notice.call_count, 0)
@override_config({"mau_limit_alerting": False})
def test_check_hs_disabled_unaffected_by_mau_alert_suppression(self): def test_check_hs_disabled_unaffected_by_mau_alert_suppression(self):
""" """
Test that when a server is disabled, that MAU limit alerting is ignored. Test that when a server is disabled, that MAU limit alerting is ignored.
""" """
self.hs.config.mau_limit_alerting = False
self._rlsn._auth.check_auth_blocking = Mock( self._rlsn._auth.check_auth_blocking = Mock(
return_value=defer.succeed(None), return_value=defer.succeed(None),
side_effect=ResourceLimitError( side_effect=ResourceLimitError(
@ -187,12 +193,12 @@ class TestResourceLimitsServerNotices(unittest.HomeserverTestCase):
# Would be better to check contents, but 2 calls == set blocking event # Would be better to check contents, but 2 calls == set blocking event
self.assertEqual(self._send_notice.call_count, 2) self.assertEqual(self._send_notice.call_count, 2)
@override_config({"mau_limit_alerting": False})
def test_maybe_send_server_notice_when_alerting_suppressed_room_blocked(self): def test_maybe_send_server_notice_when_alerting_suppressed_room_blocked(self):
""" """
When the room is already in a blocked state, test that when alerting When the room is already in a blocked state, test that when alerting
is suppressed that the room is returned to an unblocked state. is suppressed that the room is returned to an unblocked state.
""" """
self.hs.config.mau_limit_alerting = False
self._rlsn._auth.check_auth_blocking = Mock( self._rlsn._auth.check_auth_blocking = Mock(
return_value=defer.succeed(None), return_value=defer.succeed(None),
side_effect=ResourceLimitError( side_effect=ResourceLimitError(

View File

@ -23,6 +23,7 @@ from synapse.http.site import XForwardedForRequest
from synapse.rest.client.v1 import login from synapse.rest.client.v1 import login
from tests import unittest from tests import unittest
from tests.unittest import override_config
class ClientIpStoreTestCase(unittest.HomeserverTestCase): class ClientIpStoreTestCase(unittest.HomeserverTestCase):
@ -137,9 +138,8 @@ class ClientIpStoreTestCase(unittest.HomeserverTestCase):
], ],
) )
@override_config({"limit_usage_by_mau": False, "max_mau_value": 50})
def test_disabled_monthly_active_user(self): def test_disabled_monthly_active_user(self):
self.hs.config.limit_usage_by_mau = False
self.hs.config.max_mau_value = 50
user_id = "@user:server" user_id = "@user:server"
self.get_success( self.get_success(
self.store.insert_client_ip( self.store.insert_client_ip(
@ -149,9 +149,8 @@ class ClientIpStoreTestCase(unittest.HomeserverTestCase):
active = self.get_success(self.store.user_last_seen_monthly_active(user_id)) active = self.get_success(self.store.user_last_seen_monthly_active(user_id))
self.assertFalse(active) self.assertFalse(active)
@override_config({"limit_usage_by_mau": True, "max_mau_value": 50})
def test_adding_monthly_active_user_when_full(self): def test_adding_monthly_active_user_when_full(self):
self.hs.config.limit_usage_by_mau = True
self.hs.config.max_mau_value = 50
lots_of_users = 100 lots_of_users = 100
user_id = "@user:server" user_id = "@user:server"
@ -166,9 +165,8 @@ class ClientIpStoreTestCase(unittest.HomeserverTestCase):
active = self.get_success(self.store.user_last_seen_monthly_active(user_id)) active = self.get_success(self.store.user_last_seen_monthly_active(user_id))
self.assertFalse(active) self.assertFalse(active)
@override_config({"limit_usage_by_mau": True, "max_mau_value": 50})
def test_adding_monthly_active_user_when_space(self): def test_adding_monthly_active_user_when_space(self):
self.hs.config.limit_usage_by_mau = True
self.hs.config.max_mau_value = 50
user_id = "@user:server" user_id = "@user:server"
active = self.get_success(self.store.user_last_seen_monthly_active(user_id)) active = self.get_success(self.store.user_last_seen_monthly_active(user_id))
self.assertFalse(active) self.assertFalse(active)
@ -184,9 +182,8 @@ class ClientIpStoreTestCase(unittest.HomeserverTestCase):
active = self.get_success(self.store.user_last_seen_monthly_active(user_id)) active = self.get_success(self.store.user_last_seen_monthly_active(user_id))
self.assertTrue(active) self.assertTrue(active)
@override_config({"limit_usage_by_mau": True, "max_mau_value": 50})
def test_updating_monthly_active_user_when_space(self): def test_updating_monthly_active_user_when_space(self):
self.hs.config.limit_usage_by_mau = True
self.hs.config.max_mau_value = 50
user_id = "@user:server" user_id = "@user:server"
self.get_success(self.store.register_user(user_id=user_id, password_hash=None)) self.get_success(self.store.register_user(user_id=user_id, password_hash=None))

View File

@ -19,94 +19,106 @@ from twisted.internet import defer
from synapse.api.constants import UserTypes from synapse.api.constants import UserTypes
from tests import unittest from tests import unittest
from tests.unittest import default_config, override_config
FORTY_DAYS = 40 * 24 * 60 * 60 FORTY_DAYS = 40 * 24 * 60 * 60
def gen_3pids(count):
"""Generate `count` threepids as a list."""
return [
{"medium": "email", "address": "user%i@matrix.org" % i} for i in range(count)
]
class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase): class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase):
def make_homeserver(self, reactor, clock): def default_config(self):
config = default_config("test")
hs = self.setup_test_homeserver() config.update({"limit_usage_by_mau": True, "max_mau_value": 50})
self.store = hs.get_datastore()
hs.config.limit_usage_by_mau = True
hs.config.max_mau_value = 50
# apply any additional config which was specified via the override_config
# decorator.
if self._extra_config is not None:
config.update(self._extra_config)
return config
def prepare(self, reactor, clock, homeserver):
self.store = homeserver.get_datastore()
# Advance the clock a bit # Advance the clock a bit
reactor.advance(FORTY_DAYS) reactor.advance(FORTY_DAYS)
return hs @override_config({"max_mau_value": 3, "mau_limit_reserved_threepids": gen_3pids(3)})
def test_initialise_reserved_users(self): def test_initialise_reserved_users(self):
self.hs.config.max_mau_value = 5 threepids = self.hs.config.mau_limits_reserved_threepids
# register three users, of which two have reserved 3pids, and a third
# which is a support user.
user1 = "@user1:server" user1 = "@user1:server"
user1_email = "user1@matrix.org" user1_email = threepids[0]["address"]
user2 = "@user2:server" user2 = "@user2:server"
user2_email = "user2@matrix.org" user2_email = threepids[1]["address"]
user3 = "@user3:server" user3 = "@user3:server"
user3_email = "user3@matrix.org"
threepids = [ self.store.register_user(user_id=user1)
{"medium": "email", "address": user1_email}, self.store.register_user(user_id=user2)
{"medium": "email", "address": user2_email}, self.store.register_user(user_id=user3, user_type=UserTypes.SUPPORT)
{"medium": "email", "address": user3_email},
]
self.hs.config.mau_limits_reserved_threepids = threepids
# -1 because user3 is a support user and does not count
user_num = len(threepids) - 1
self.store.register_user(user_id=user1, password_hash=None)
self.store.register_user(user_id=user2, password_hash=None)
self.store.register_user(
user_id=user3, password_hash=None, user_type=UserTypes.SUPPORT
)
self.pump() self.pump()
now = int(self.hs.get_clock().time_msec()) now = int(self.hs.get_clock().time_msec())
self.store.user_add_threepid(user1, "email", user1_email, now, now) self.store.user_add_threepid(user1, "email", user1_email, now, now)
self.store.user_add_threepid(user2, "email", user2_email, now, now) self.store.user_add_threepid(user2, "email", user2_email, now, now)
# XXX why are we doing this here? this function is only run at startup
# so it is odd to re-run it here.
self.store.db.runInteraction( self.store.db.runInteraction(
"initialise", self.store._initialise_reserved_users, threepids "initialise", self.store._initialise_reserved_users, threepids
) )
self.pump() self.pump()
active_count = self.store.get_monthly_active_count() # the number of users we expect will be counted against the mau limit
# -1 because user3 is a support user and does not count
user_num = len(threepids) - 1
# Test total counts, ensure user3 (support user) is not counted # Check the number of active users. Ensure user3 (support user) is not counted
self.assertEquals(self.get_success(active_count), user_num) active_count = self.get_success(self.store.get_monthly_active_count())
self.assertEquals(active_count, user_num)
# Test user is marked as active # Test each of the registered users is marked as active
timestamp = self.store.user_last_seen_monthly_active(user1) timestamp = self.store.user_last_seen_monthly_active(user1)
self.assertTrue(self.get_success(timestamp)) self.assertTrue(self.get_success(timestamp))
timestamp = self.store.user_last_seen_monthly_active(user2) timestamp = self.store.user_last_seen_monthly_active(user2)
self.assertTrue(self.get_success(timestamp)) self.assertTrue(self.get_success(timestamp))
# Test that users are never removed from the db. # Test that users with reserved 3pids are not removed from the MAU table
# XXX some of this is redundant. poking things into the config shouldn't
# work, and in any case it's not obvious what we expect to happen when
# we advance the reactor.
self.hs.config.max_mau_value = 0 self.hs.config.max_mau_value = 0
self.reactor.advance(FORTY_DAYS) self.reactor.advance(FORTY_DAYS)
self.hs.config.max_mau_value = 5 self.hs.config.max_mau_value = 5
self.store.reap_monthly_active_users() self.store.reap_monthly_active_users()
self.pump() self.pump()
active_count = self.store.get_monthly_active_count() active_count = self.store.get_monthly_active_count()
self.assertEquals(self.get_success(active_count), user_num) self.assertEquals(self.get_success(active_count), user_num)
# Test that regular users are removed from the db # Add some more users and check they are counted as active
ru_count = 2 ru_count = 2
self.store.upsert_monthly_active_user("@ru1:server") self.store.upsert_monthly_active_user("@ru1:server")
self.store.upsert_monthly_active_user("@ru2:server") self.store.upsert_monthly_active_user("@ru2:server")
self.pump() self.pump()
active_count = self.store.get_monthly_active_count() active_count = self.store.get_monthly_active_count()
self.assertEqual(self.get_success(active_count), user_num + ru_count) self.assertEqual(self.get_success(active_count), user_num + ru_count)
self.hs.config.max_mau_value = user_num
# now run the reaper and check that the number of active users is reduced
# to max_mau_value
self.store.reap_monthly_active_users() self.store.reap_monthly_active_users()
self.pump() self.pump()
active_count = self.store.get_monthly_active_count() active_count = self.store.get_monthly_active_count()
self.assertEquals(self.get_success(active_count), user_num) self.assertEquals(self.get_success(active_count), 3)
def test_can_insert_and_count_mau(self): def test_can_insert_and_count_mau(self):
count = self.store.get_monthly_active_count() count = self.store.get_monthly_active_count()
@ -136,8 +148,8 @@ class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase):
result = self.store.user_last_seen_monthly_active(user_id3) result = self.store.user_last_seen_monthly_active(user_id3)
self.assertNotEqual(self.get_success(result), 0) self.assertNotEqual(self.get_success(result), 0)
@override_config({"max_mau_value": 5})
def test_reap_monthly_active_users(self): def test_reap_monthly_active_users(self):
self.hs.config.max_mau_value = 5
initial_users = 10 initial_users = 10
for i in range(initial_users): for i in range(initial_users):
self.store.upsert_monthly_active_user("@user%d:server" % i) self.store.upsert_monthly_active_user("@user%d:server" % i)
@ -158,19 +170,19 @@ class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase):
count = self.store.get_monthly_active_count() count = self.store.get_monthly_active_count()
self.assertEquals(self.get_success(count), 0) self.assertEquals(self.get_success(count), 0)
# Note that below says mau_limit (no s), this is the name of the config
# value, although it gets stored on the config object as mau_limits.
@override_config({"max_mau_value": 5, "mau_limit_reserved_threepids": gen_3pids(5)})
def test_reap_monthly_active_users_reserved_users(self): def test_reap_monthly_active_users_reserved_users(self):
""" Tests that reaping correctly handles reaping where reserved users are """ Tests that reaping correctly handles reaping where reserved users are
present""" present"""
threepids = self.hs.config.mau_limits_reserved_threepids
self.hs.config.max_mau_value = 5 initial_users = len(threepids)
initial_users = 5
reserved_user_number = initial_users - 1 reserved_user_number = initial_users - 1
threepids = []
for i in range(initial_users): for i in range(initial_users):
user = "@user%d:server" % i user = "@user%d:server" % i
email = "user%d@example.com" % i email = "user%d@matrix.org" % i
self.get_success(self.store.upsert_monthly_active_user(user)) self.get_success(self.store.upsert_monthly_active_user(user))
threepids.append({"medium": "email", "address": email})
# Need to ensure that the most recent entries in the # Need to ensure that the most recent entries in the
# monthly_active_users table are reserved # monthly_active_users table are reserved
now = int(self.hs.get_clock().time_msec()) now = int(self.hs.get_clock().time_msec())
@ -182,7 +194,6 @@ class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase):
self.store.user_add_threepid(user, "email", email, now, now) self.store.user_add_threepid(user, "email", email, now, now)
) )
self.hs.config.mau_limits_reserved_threepids = threepids
self.store.db.runInteraction( self.store.db.runInteraction(
"initialise", self.store._initialise_reserved_users, threepids "initialise", self.store._initialise_reserved_users, threepids
) )
@ -279,11 +290,11 @@ class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase):
self.pump() self.pump()
self.assertEqual(self.get_success(count), 0) self.assertEqual(self.get_success(count), 0)
# Note that the max_mau_value setting should not matter.
@override_config(
{"limit_usage_by_mau": False, "mau_stats_only": True, "max_mau_value": 1}
)
def test_track_monthly_users_without_cap(self): def test_track_monthly_users_without_cap(self):
self.hs.config.limit_usage_by_mau = False
self.hs.config.mau_stats_only = True
self.hs.config.max_mau_value = 1 # should not matter
count = self.store.get_monthly_active_count() count = self.store.get_monthly_active_count()
self.assertEqual(0, self.get_success(count)) self.assertEqual(0, self.get_success(count))
@ -294,9 +305,8 @@ class MonthlyActiveUsersTestCase(unittest.HomeserverTestCase):
count = self.store.get_monthly_active_count() count = self.store.get_monthly_active_count()
self.assertEqual(2, self.get_success(count)) self.assertEqual(2, self.get_success(count))
@override_config({"limit_usage_by_mau": False, "mau_stats_only": False})
def test_no_users_when_not_tracking(self): def test_no_users_when_not_tracking(self):
self.hs.config.limit_usage_by_mau = False
self.hs.config.mau_stats_only = False
self.store.upsert_monthly_active_user = Mock() self.store.upsert_monthly_active_user = Mock()
self.store.populate_monthly_active_users("@user:sever") self.store.populate_monthly_active_users("@user:sever")

View File

@ -17,47 +17,44 @@
import json import json
from mock import Mock
from synapse.api.auth_blocking import AuthBlocking
from synapse.api.constants import LoginType from synapse.api.constants import LoginType
from synapse.api.errors import Codes, HttpResponseException, SynapseError from synapse.api.errors import Codes, HttpResponseException, SynapseError
from synapse.rest.client.v2_alpha import register, sync from synapse.rest.client.v2_alpha import register, sync
from tests import unittest from tests import unittest
from tests.unittest import override_config
from tests.utils import default_config
class TestMauLimit(unittest.HomeserverTestCase): class TestMauLimit(unittest.HomeserverTestCase):
servlets = [register.register_servlets, sync.register_servlets] servlets = [register.register_servlets, sync.register_servlets]
def make_homeserver(self, reactor, clock): def default_config(self):
config = default_config("test")
self.hs = self.setup_test_homeserver( config.update(
"red", http_client=None, federation_client=Mock() {
"registrations_require_3pid": [],
"limit_usage_by_mau": True,
"max_mau_value": 2,
"mau_trial_days": 0,
"server_notices": {
"system_mxid_localpart": "server",
"room_name": "Test Server Notice Room",
},
}
) )
self.store = self.hs.get_datastore() # apply any additional config which was specified via the override_config
# decorator.
if self._extra_config is not None:
config.update(self._extra_config)
self.hs.config.registrations_require_3pid = [] return config
self.hs.config.enable_registration_captcha = False
self.hs.config.recaptcha_public_key = []
self.hs.config.limit_usage_by_mau = True def prepare(self, reactor, clock, homeserver):
self.hs.config.hs_disabled = False self.store = homeserver.get_datastore()
self.hs.config.max_mau_value = 2
self.hs.config.server_notices_mxid = "@server:red"
self.hs.config.server_notices_mxid_display_name = None
self.hs.config.server_notices_mxid_avatar_url = None
self.hs.config.server_notices_room_name = "Test Server Notice Room"
self.hs.config.mau_trial_days = 0
# AuthBlocking reads config options during hs creation. Recreate the
# hs' copy of AuthBlocking after we've updated config values above
self.auth_blocking = AuthBlocking(self.hs)
self.hs.get_auth()._auth_blocking = self.auth_blocking
return self.hs
def test_simple_deny_mau(self): def test_simple_deny_mau(self):
# Create and sync so that the MAU counts get updated # Create and sync so that the MAU counts get updated
@ -66,6 +63,9 @@ class TestMauLimit(unittest.HomeserverTestCase):
token2 = self.create_user("kermit2") token2 = self.create_user("kermit2")
self.do_sync_for_user(token2) self.do_sync_for_user(token2)
# check we're testing what we think we are: there should be two active users
self.assertEqual(self.get_success(self.store.get_monthly_active_count()), 2)
# We've created and activated two users, we shouldn't be able to # We've created and activated two users, we shouldn't be able to
# register new users # register new users
with self.assertRaises(SynapseError) as cm: with self.assertRaises(SynapseError) as cm:
@ -93,9 +93,8 @@ class TestMauLimit(unittest.HomeserverTestCase):
token3 = self.create_user("kermit3") token3 = self.create_user("kermit3")
self.do_sync_for_user(token3) self.do_sync_for_user(token3)
@override_config({"mau_trial_days": 1})
def test_trial_delay(self): def test_trial_delay(self):
self.hs.config.mau_trial_days = 1
# We should be able to register more than the limit initially # We should be able to register more than the limit initially
token1 = self.create_user("kermit1") token1 = self.create_user("kermit1")
self.do_sync_for_user(token1) self.do_sync_for_user(token1)
@ -127,8 +126,8 @@ class TestMauLimit(unittest.HomeserverTestCase):
self.assertEqual(e.code, 403) self.assertEqual(e.code, 403)
self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED) self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
@override_config({"mau_trial_days": 1})
def test_trial_users_cant_come_back(self): def test_trial_users_cant_come_back(self):
self.auth_blocking._mau_trial_days = 1
self.hs.config.mau_trial_days = 1 self.hs.config.mau_trial_days = 1
# We should be able to register more than the limit initially # We should be able to register more than the limit initially
@ -176,11 +175,11 @@ class TestMauLimit(unittest.HomeserverTestCase):
self.assertEqual(e.code, 403) self.assertEqual(e.code, 403)
self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED) self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
@override_config(
# max_mau_value should not matter
{"max_mau_value": 1, "limit_usage_by_mau": False, "mau_stats_only": True}
)
def test_tracked_but_not_limited(self): def test_tracked_but_not_limited(self):
self.auth_blocking._max_mau_value = 1 # should not matter
self.auth_blocking._limit_usage_by_mau = False
self.hs.config.mau_stats_only = True
# Simply being able to create 2 users indicates that the # Simply being able to create 2 users indicates that the
# limit was not reached. # limit was not reached.
token1 = self.create_user("kermit1") token1 = self.create_user("kermit1")