diff --git a/tests/handlers/test_stats.py b/tests/handlers/test_stats.py
index ac6cdd6116..b4db7fed74 100644
--- a/tests/handlers/test_stats.py
+++ b/tests/handlers/test_stats.py
@@ -22,8 +22,10 @@ from synapse.rest import admin
from synapse.rest.client.v1 import login, room
from tests import unittest
-# The expected number of state events in a fresh room.
-EXPECTED_NUM_STATE_EVENTS_IN_FRESH_ROOM = 5
+# The expected number of state events in a fresh public room.
+EXPT_NUM_STATE_EVTS_IN_FRESH_PUBLIC_ROOM = 5
+# The expected number of state events in a fresh private room.
+EXPT_NUM_STATE_EVTS_IN_FRESH_PRIVATE_ROOM = 6
class StatsRoomTests(unittest.HomeserverTestCase):
@@ -97,7 +99,7 @@ class StatsRoomTests(unittest.HomeserverTestCase):
)
)
- def _complete_background_initial_update(self):
+ def _perform_background_initial_update(self):
# Do the initial population of the stats via the background update
self._add_background_updates()
@@ -371,29 +373,47 @@ class StatsRoomTests(unittest.HomeserverTestCase):
u1token = self.login("u1", "pass")
r1 = self.helper.create_room_as(u1, tok=u1token)
r1stats = self._get_current_stats("room", r1)
+ r2 = self.helper.create_room_as(u1, tok=u1token, is_public=False)
+ r2stats = self._get_current_stats("room", r2)
self.assertIsNotNone(r1stats)
+ self.assertIsNotNone(r2stats)
# row is complete
self.assertIsNotNone(r1stats["completed_delta_stream_id"])
+ self.assertIsNotNone(r2stats["completed_delta_stream_id"])
# contains the default things you'd expect in a fresh room
self.assertEqual(
r1stats["total_events"],
- EXPECTED_NUM_STATE_EVENTS_IN_FRESH_ROOM,
+ EXPT_NUM_STATE_EVTS_IN_FRESH_PUBLIC_ROOM,
+ "Wrong number of total_events in new room's stats!"
+ " You may need to update this if more state events are added to"
+ " the room creation process.",
+ )
+ self.assertEqual(
+ r2stats["total_events"],
+ EXPT_NUM_STATE_EVTS_IN_FRESH_PRIVATE_ROOM,
"Wrong number of total_events in new room's stats!"
" You may need to update this if more state events are added to"
" the room creation process.",
)
self.assertEqual(
- r1stats["current_state_events"], EXPECTED_NUM_STATE_EVENTS_IN_FRESH_ROOM
+ r1stats["current_state_events"], EXPT_NUM_STATE_EVTS_IN_FRESH_PUBLIC_ROOM
+ )
+ self.assertEqual(
+ r2stats["current_state_events"], EXPT_NUM_STATE_EVTS_IN_FRESH_PRIVATE_ROOM
)
self.assertEqual(r1stats["joined_members"], 1)
self.assertEqual(r1stats["invited_members"], 0)
self.assertEqual(r1stats["banned_members"], 0)
+ self.assertEqual(r2stats["joined_members"], 1)
+ self.assertEqual(r2stats["invited_members"], 0)
+ self.assertEqual(r2stats["banned_members"], 0)
+
def test_send_message_increments_total_events(self):
"""
When we send a message, it increments total_events.
@@ -659,3 +679,191 @@ class StatsRoomTests(unittest.HomeserverTestCase):
self.assertEqual(
r1stats_post["joined_members"] - r1stats_ante["joined_members"], -1
)
+
+ def test_initial_background_update(self):
+ """
+ Test that statistics can be generated by the initial background update
+ handler.
+
+ This test also tests that stats rows are not created for new subjects
+ when stats are disabled. However, it may be desirable to change this
+ behaviour eventually to still keep current rows.
+ """
+
+ self.hs.config.stats_enabled = False
+
+ u1 = self.register_user("u1", "pass")
+ u1token = self.login("u1", "pass")
+ r1 = self.helper.create_room_as(u1, tok=u1token)
+
+ # test that these subjects, which were created during a time of disabled
+ # stats, do not have stats.
+ self.assertIsNone(self._get_current_stats("room", r1))
+ self.assertIsNone(self._get_current_stats("user", u1))
+
+ self.hs.config.stats_enabled = True
+
+ self._perform_background_initial_update()
+
+ r1stats = self._get_current_stats("room", r1)
+ u1stats = self._get_current_stats("user", u1)
+
+ self.assertIsNotNone(r1stats["completed_delta_stream_id"])
+ self.assertIsNotNone(u1stats["completed_delta_stream_id"])
+
+ self.assertEqual(r1stats["joined_members"], 1)
+ self.assertEqual(
+ r1stats["total_events"], EXPT_NUM_STATE_EVTS_IN_FRESH_PUBLIC_ROOM
+ )
+ self.assertEqual(
+ r1stats["current_state_events"], EXPT_NUM_STATE_EVTS_IN_FRESH_PUBLIC_ROOM
+ )
+
+ self.assertEqual(u1stats["public_rooms"], 1)
+
+ def test_incomplete_stats(self):
+ """
+ This tests that we track incomplete statistics.
+
+ We first test that incomplete stats are incrementally generated,
+ following the preparation of a background regen.
+
+ We then test that these incomplete rows are completed by the background
+ regen.
+ """
+
+ u1 = self.register_user("u1", "pass")
+ u1token = self.login("u1", "pass")
+ u2 = self.register_user("u2", "pass")
+ u2token = self.login("u2", "pass")
+ u3 = self.register_user("u3", "pass")
+ r1 = self.helper.create_room_as(u1, tok=u1token, is_public=False)
+
+ # preparation stage of the initial background update
+ # Ugh, have to reset this flag
+ self.store._all_done = False
+
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {"update_name": "populate_stats_prepare", "progress_json": "{}"},
+ )
+ )
+
+ self.get_success(
+ self.store._simple_delete(
+ "room_stats_current", {"1": 1}, "test_delete_stats"
+ )
+ )
+ self.get_success(
+ self.store._simple_delete(
+ "user_stats_current", {"1": 1}, "test_delete_stats"
+ )
+ )
+
+ while not self.get_success(self.store.has_completed_background_updates()):
+ self.get_success(self.store.do_next_background_update(100), by=0.1)
+
+ r1stats_ante = self._get_current_stats("room", r1)
+ u1stats_ante = self._get_current_stats("user", u1)
+ u2stats_ante = self._get_current_stats("user", u2)
+
+ self.helper.invite(r1, u1, u2, tok=u1token)
+ self.helper.join(r1, u2, tok=u2token)
+ self.helper.invite(r1, u1, u3, tok=u1token)
+ self.helper.send(r1, "thou shalt yield", tok=u1token)
+
+ r1stats_post = self._get_current_stats("room", r1)
+ u1stats_post = self._get_current_stats("user", u1)
+ u2stats_post = self._get_current_stats("user", u2)
+
+ # now let the background update continue & finish
+
+ self.store._all_done = False
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {
+ "update_name": "populate_stats_process_rooms",
+ "progress_json": "{}",
+ "depends_on": "populate_stats_prepare",
+ },
+ )
+ )
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {
+ "update_name": "populate_stats_process_users",
+ "progress_json": "{}",
+ "depends_on": "populate_stats_process_rooms",
+ },
+ )
+ )
+ self.get_success(
+ self.store._simple_insert(
+ "background_updates",
+ {
+ "update_name": "populate_stats_cleanup",
+ "progress_json": "{}",
+ "depends_on": "populate_stats_process_users",
+ },
+ )
+ )
+
+ while not self.get_success(self.store.has_completed_background_updates()):
+ self.get_success(self.store.do_next_background_update(100), by=0.1)
+
+ r1stats_complete = self._get_current_stats("room", r1)
+ u1stats_complete = self._get_current_stats("user", u1)
+ u2stats_complete = self._get_current_stats("user", u2)
+
+ # now we make our assertions
+
+ # first check that none of the stats rows were complete before
+ # the background update occurred.
+ self.assertIsNone(r1stats_ante["completed_delta_stream_id"])
+ self.assertIsNone(r1stats_post["completed_delta_stream_id"])
+ self.assertIsNone(u1stats_ante["completed_delta_stream_id"])
+ self.assertIsNone(u1stats_post["completed_delta_stream_id"])
+ self.assertIsNone(u2stats_ante["completed_delta_stream_id"])
+ self.assertIsNone(u2stats_post["completed_delta_stream_id"])
+
+ # check that _ante rows are all skeletons without any deltas applied
+ self.assertEqual(r1stats_ante["joined_members"], 0)
+ self.assertEqual(r1stats_ante["invited_members"], 0)
+ self.assertEqual(r1stats_ante["total_events"], 0)
+ self.assertEqual(r1stats_ante["current_state_events"], 0)
+
+ self.assertEqual(u1stats_ante["public_rooms"], 0)
+ self.assertEqual(u1stats_ante["private_rooms"], 0)
+ self.assertEqual(u2stats_ante["public_rooms"], 0)
+ self.assertEqual(u2stats_ante["private_rooms"], 0)
+
+ # check that _post rows have the expected deltas applied
+ self.assertEqual(r1stats_post["joined_members"], 1)
+ self.assertEqual(r1stats_post["invited_members"], 1)
+ self.assertEqual(r1stats_post["total_events"], 4)
+ self.assertEqual(r1stats_post["current_state_events"], 2)
+
+ self.assertEqual(u1stats_post["public_rooms"], 0)
+ self.assertEqual(u1stats_post["private_rooms"], 0)
+ self.assertEqual(u2stats_post["public_rooms"], 0)
+ self.assertEqual(u2stats_post["private_rooms"], 1)
+
+ # check that _complete rows are complete and correct
+ self.assertEqual(r1stats_complete["joined_members"], 2)
+ self.assertEqual(r1stats_complete["invited_members"], 1)
+ self.assertEqual(
+ r1stats_complete["total_events"],
+ 4 + EXPT_NUM_STATE_EVTS_IN_FRESH_PRIVATE_ROOM,
+ )
+ self.assertEqual(
+ r1stats_complete["current_state_events"],
+ 2 + EXPT_NUM_STATE_EVTS_IN_FRESH_PRIVATE_ROOM,
+ )
+
+ self.assertEqual(u1stats_complete["public_rooms"], 0)
+ self.assertEqual(u1stats_complete["private_rooms"], 1)
+ self.assertEqual(u2stats_complete["public_rooms"], 0)
+ self.assertEqual(u2stats_complete["private_rooms"], 1)
|