diff --git a/tests/api/test_auth.py b/tests/api/test_auth.py
index a82d737e71..5dc3398300 100644
--- a/tests/api/test_auth.py
+++ b/tests/api/test_auth.py
@@ -444,3 +444,28 @@ class AuthTestCase(unittest.TestCase):
self.assertEqual("Guest access token used for regular user", cm.exception.msg)
self.store.get_user_by_id.assert_called_with(USER_ID)
+
+ @defer.inlineCallbacks
+ def test_blocking_mau(self):
+ self.hs.config.limit_usage_by_mau = False
+ self.hs.config.max_mau_value = 50
+ lots_of_users = 100
+ small_number_of_users = 1
+
+ # Ensure no error thrown
+ yield self.auth.check_auth_blocking()
+
+ self.hs.config.limit_usage_by_mau = True
+
+ self.store.get_monthly_active_count = Mock(
+ return_value=defer.succeed(lots_of_users)
+ )
+
+ with self.assertRaises(AuthError):
+ yield self.auth.check_auth_blocking()
+
+ # Ensure does not throw an error
+ self.store.get_monthly_active_count = Mock(
+ return_value=defer.succeed(small_number_of_users)
+ )
+ yield self.auth.check_auth_blocking()
diff --git a/tests/handlers/test_auth.py b/tests/handlers/test_auth.py
index 55eab9e9cf..8a9bf2d5fd 100644
--- a/tests/handlers/test_auth.py
+++ b/tests/handlers/test_auth.py
@@ -132,14 +132,14 @@ class AuthTestCase(unittest.TestCase):
@defer.inlineCallbacks
def test_mau_limits_exceeded(self):
self.hs.config.limit_usage_by_mau = True
- self.hs.get_datastore().count_monthly_users = Mock(
+ self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.large_number_of_users)
)
with self.assertRaises(AuthError):
yield self.auth_handler.get_access_token_for_user_id('user_a')
- self.hs.get_datastore().count_monthly_users = Mock(
+ self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.large_number_of_users)
)
with self.assertRaises(AuthError):
@@ -151,13 +151,13 @@ class AuthTestCase(unittest.TestCase):
def test_mau_limits_not_exceeded(self):
self.hs.config.limit_usage_by_mau = True
- self.hs.get_datastore().count_monthly_users = Mock(
+ self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.small_number_of_users)
)
# Ensure does not raise exception
yield self.auth_handler.get_access_token_for_user_id('user_a')
- self.hs.get_datastore().count_monthly_users = Mock(
+ self.hs.get_datastore().get_monthly_active_count = Mock(
return_value=defer.succeed(self.small_number_of_users)
)
yield self.auth_handler.validate_short_term_login_token_and_get_user_id(
diff --git a/tests/handlers/test_register.py b/tests/handlers/test_register.py
index 0937d71cf6..4ea59a58de 100644
--- a/tests/handlers/test_register.py
+++ b/tests/handlers/test_register.py
@@ -50,6 +50,10 @@ class RegistrationTestCase(unittest.TestCase):
self.hs.get_macaroon_generator = Mock(return_value=self.macaroon_generator)
self.hs.handlers = RegistrationHandlers(self.hs)
self.handler = self.hs.get_handlers().registration_handler
+ self.store = self.hs.get_datastore()
+ self.hs.config.max_mau_value = 50
+ self.lots_of_users = 100
+ self.small_number_of_users = 1
@defer.inlineCallbacks
def test_user_is_created_and_logged_in_if_doesnt_exist(self):
@@ -80,51 +84,43 @@ class RegistrationTestCase(unittest.TestCase):
self.assertEquals(result_token, 'secret')
@defer.inlineCallbacks
- def test_cannot_register_when_mau_limits_exceeded(self):
- local_part = "someone"
- display_name = "someone"
- requester = create_requester("@as:test")
- store = self.hs.get_datastore()
+ def test_mau_limits_when_disabled(self):
self.hs.config.limit_usage_by_mau = False
- self.hs.config.max_mau_value = 50
- lots_of_users = 100
- small_number_users = 1
-
- store.count_monthly_users = Mock(return_value=defer.succeed(lots_of_users))
-
# Ensure does not throw exception
- yield self.handler.get_or_create_user(requester, 'a', display_name)
+ yield self.handler.get_or_create_user("requester", 'a', "display_name")
+ @defer.inlineCallbacks
+ def test_get_or_create_user_mau_not_blocked(self):
self.hs.config.limit_usage_by_mau = True
-
- with self.assertRaises(RegistrationError):
- yield self.handler.get_or_create_user(requester, 'b', display_name)
-
- store.count_monthly_users = Mock(return_value=defer.succeed(small_number_users))
-
- self._macaroon_mock_generator("another_secret")
-
+ self.store.count_monthly_users = Mock(
+ return_value=defer.succeed(self.small_number_of_users)
+ )
# Ensure does not throw exception
- yield self.handler.get_or_create_user("@neil:matrix.org", 'c', "Neil")
-
- self._macaroon_mock_generator("another another secret")
- store.count_monthly_users = Mock(return_value=defer.succeed(lots_of_users))
+ yield self.handler.get_or_create_user("@user:server", 'c', "User")
+ @defer.inlineCallbacks
+ def test_get_or_create_user_mau_blocked(self):
+ self.hs.config.limit_usage_by_mau = True
+ self.store.get_monthly_active_count = Mock(
+ return_value=defer.succeed(self.lots_of_users)
+ )
with self.assertRaises(RegistrationError):
- yield self.handler.register(localpart=local_part)
+ yield self.handler.get_or_create_user("requester", 'b', "display_name")
- self._macaroon_mock_generator("another another secret")
- store.count_monthly_users = Mock(return_value=defer.succeed(lots_of_users))
+ @defer.inlineCallbacks
+ def test_register_mau_blocked(self):
+ self.hs.config.limit_usage_by_mau = True
+ self.store.get_monthly_active_count = Mock(
+ return_value=defer.succeed(self.lots_of_users)
+ )
+ with self.assertRaises(RegistrationError):
+ yield self.handler.register(localpart="local_part")
+ @defer.inlineCallbacks
+ def test_register_saml2_mau_blocked(self):
+ self.hs.config.limit_usage_by_mau = True
+ self.store.get_monthly_active_count = Mock(
+ return_value=defer.succeed(self.lots_of_users)
+ )
with self.assertRaises(RegistrationError):
- yield self.handler.register_saml2(local_part)
-
- def _macaroon_mock_generator(self, secret):
- """
- Reset macaroon generator in the case where the test creates multiple users
- """
- macaroon_generator = Mock(
- generate_access_token=Mock(return_value=secret))
- self.hs.get_macaroon_generator = Mock(return_value=macaroon_generator)
- self.hs.handlers = RegistrationHandlers(self.hs)
- self.handler = self.hs.get_handlers().registration_handler
+ yield self.handler.register_saml2(localpart="local_part")
diff --git a/tests/storage/test__init__.py b/tests/storage/test__init__.py
deleted file mode 100644
index f19cb1265c..0000000000
--- a/tests/storage/test__init__.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2018 New Vector Ltd
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from twisted.internet import defer
-
-import tests.utils
-
-
-class InitTestCase(tests.unittest.TestCase):
- def __init__(self, *args, **kwargs):
- super(InitTestCase, self).__init__(*args, **kwargs)
- self.store = None # type: synapse.storage.DataStore
-
- @defer.inlineCallbacks
- def setUp(self):
- hs = yield tests.utils.setup_test_homeserver()
-
- hs.config.max_mau_value = 50
- hs.config.limit_usage_by_mau = True
- self.store = hs.get_datastore()
- self.clock = hs.get_clock()
-
- @defer.inlineCallbacks
- def test_count_monthly_users(self):
- count = yield self.store.count_monthly_users()
- self.assertEqual(0, count)
-
- yield self._insert_user_ips("@user:server1")
- yield self._insert_user_ips("@user:server2")
-
- count = yield self.store.count_monthly_users()
- self.assertEqual(2, count)
-
- @defer.inlineCallbacks
- def _insert_user_ips(self, user):
- """
- Helper function to populate user_ips without using batch insertion infra
- args:
- user (str): specify username i.e. @user:server.com
- """
- yield self.store._simple_upsert(
- table="user_ips",
- keyvalues={
- "user_id": user,
- "access_token": "access_token",
- "ip": "ip",
- "user_agent": "user_agent",
- "device_id": "device_id",
- },
- values={
- "last_seen": self.clock.time_msec(),
- }
- )
diff --git a/tests/storage/test_client_ips.py b/tests/storage/test_client_ips.py
index bd6fda6cb1..7a58c6eb24 100644
--- a/tests/storage/test_client_ips.py
+++ b/tests/storage/test_client_ips.py
@@ -12,6 +12,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+from mock import Mock
from twisted.internet import defer
@@ -27,9 +28,9 @@ class ClientIpStoreTestCase(tests.unittest.TestCase):
@defer.inlineCallbacks
def setUp(self):
- hs = yield tests.utils.setup_test_homeserver()
- self.store = hs.get_datastore()
- self.clock = hs.get_clock()
+ self.hs = yield tests.utils.setup_test_homeserver()
+ self.store = self.hs.get_datastore()
+ self.clock = self.hs.get_clock()
@defer.inlineCallbacks
def test_insert_new_client_ip(self):
@@ -54,3 +55,62 @@ class ClientIpStoreTestCase(tests.unittest.TestCase):
},
r
)
+
+ @defer.inlineCallbacks
+ 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"
+ yield self.store.insert_client_ip(
+ user_id, "access_token", "ip", "user_agent", "device_id",
+ )
+ active = yield self.store._user_last_seen_monthly_active(user_id)
+ self.assertFalse(active)
+
+ @defer.inlineCallbacks
+ 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
+ user_id = "@user:server"
+
+ self.store.get_monthly_active_count = Mock(
+ return_value=defer.succeed(lots_of_users)
+ )
+ yield self.store.insert_client_ip(
+ user_id, "access_token", "ip", "user_agent", "device_id",
+ )
+ active = yield self.store._user_last_seen_monthly_active(user_id)
+ self.assertFalse(active)
+
+ @defer.inlineCallbacks
+ 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"
+ active = yield self.store._user_last_seen_monthly_active(user_id)
+ self.assertFalse(active)
+
+ yield self.store.insert_client_ip(
+ user_id, "access_token", "ip", "user_agent", "device_id",
+ )
+ active = yield self.store._user_last_seen_monthly_active(user_id)
+ self.assertTrue(active)
+
+ @defer.inlineCallbacks
+ 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"
+
+ active = yield self.store._user_last_seen_monthly_active(user_id)
+ self.assertFalse(active)
+
+ yield self.store.insert_client_ip(
+ user_id, "access_token", "ip", "user_agent", "device_id",
+ )
+ yield self.store.insert_client_ip(
+ user_id, "access_token", "ip", "user_agent", "device_id",
+ )
+ active = yield self.store._user_last_seen_monthly_active(user_id)
+ self.assertTrue(active)
diff --git a/tests/storage/test_monthly_active_users.py b/tests/storage/test_monthly_active_users.py
new file mode 100644
index 0000000000..cbd480cd42
--- /dev/null
+++ b/tests/storage/test_monthly_active_users.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Copyright 2018 New Vector
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from twisted.internet import defer
+
+import tests.unittest
+import tests.utils
+from tests.utils import setup_test_homeserver
+
+FORTY_DAYS = 40 * 24 * 60 * 60
+
+
+class MonthlyActiveUsersTestCase(tests.unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ super(MonthlyActiveUsersTestCase, self).__init__(*args, **kwargs)
+
+ @defer.inlineCallbacks
+ def setUp(self):
+ self.hs = yield setup_test_homeserver()
+ self.store = self.hs.get_datastore()
+
+ @defer.inlineCallbacks
+ def test_initialise_reserved_users(self):
+
+ user1 = "@user1:server"
+ user1_email = "user1@matrix.org"
+ user2 = "@user2:server"
+ user2_email = "user2@matrix.org"
+ threepids = [
+ {'medium': 'email', 'address': user1_email},
+ {'medium': 'email', 'address': user2_email}
+ ]
+ user_num = len(threepids)
+
+ yield self.store.register(
+ user_id=user1,
+ token="123",
+ password_hash=None)
+
+ yield self.store.register(
+ user_id=user2,
+ token="456",
+ password_hash=None)
+
+ now = int(self.hs.get_clock().time_msec())
+ yield self.store.user_add_threepid(user1, "email", user1_email, now, now)
+ yield self.store.user_add_threepid(user2, "email", user2_email, now, now)
+ yield self.store.initialise_reserved_users(threepids)
+
+ active_count = yield self.store.get_monthly_active_count()
+
+ # Test total counts
+ self.assertEquals(active_count, user_num)
+
+ # Test user is marked as active
+
+ timestamp = yield self.store._user_last_seen_monthly_active(user1)
+ self.assertTrue(timestamp)
+ timestamp = yield self.store._user_last_seen_monthly_active(user2)
+ self.assertTrue(timestamp)
+
+ # Test that users are never removed from the db.
+ self.hs.config.max_mau_value = 0
+
+ self.hs.get_clock().advance_time(FORTY_DAYS)
+
+ yield self.store.reap_monthly_active_users()
+
+ active_count = yield self.store.get_monthly_active_count()
+ self.assertEquals(active_count, user_num)
+
+ @defer.inlineCallbacks
+ def test_can_insert_and_count_mau(self):
+ count = yield self.store.get_monthly_active_count()
+ self.assertEqual(0, count)
+
+ yield self.store.upsert_monthly_active_user("@user:server")
+ count = yield self.store.get_monthly_active_count()
+
+ self.assertEqual(1, count)
+
+ @defer.inlineCallbacks
+ def test__user_last_seen_monthly_active(self):
+ user_id1 = "@user1:server"
+ user_id2 = "@user2:server"
+ user_id3 = "@user3:server"
+ result = yield self.store._user_last_seen_monthly_active(user_id1)
+ self.assertFalse(result == 0)
+ yield self.store.upsert_monthly_active_user(user_id1)
+ yield self.store.upsert_monthly_active_user(user_id2)
+ result = yield self.store._user_last_seen_monthly_active(user_id1)
+ self.assertTrue(result > 0)
+ result = yield self.store._user_last_seen_monthly_active(user_id3)
+ self.assertFalse(result == 0)
+
+ @defer.inlineCallbacks
+ def test_reap_monthly_active_users(self):
+ self.hs.config.max_mau_value = 5
+ initial_users = 10
+ for i in range(initial_users):
+ yield self.store.upsert_monthly_active_user("@user%d:server" % i)
+ count = yield self.store.get_monthly_active_count()
+ self.assertTrue(count, initial_users)
+ yield self.store.reap_monthly_active_users()
+ count = yield self.store.get_monthly_active_count()
+ self.assertEquals(count, initial_users - self.hs.config.max_mau_value)
+
+ self.hs.get_clock().advance_time(FORTY_DAYS)
+ yield self.store.reap_monthly_active_users()
+ count = yield self.store.get_monthly_active_count()
+ self.assertEquals(count, 0)
diff --git a/tests/utils.py b/tests/utils.py
index 9e188a8ed4..151db4b890 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -73,6 +73,9 @@ def setup_test_homeserver(name="test", datastore=None, config=None, reactor=None
config.block_events_without_consent_error = None
config.media_storage_providers = []
config.auto_join_rooms = []
+ config.limit_usage_by_mau = False
+ config.max_mau_value = 50
+ config.mau_limits_reserved_threepids = []
# we need a sane default_room_version, otherwise attempts to create rooms will
# fail.
|