Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit da162cb

Browse files
authored
Add tests for restoring the presence state after a restart. (#16151)
1 parent 19a1cda commit da162cb

3 files changed

Lines changed: 118 additions & 1 deletion

File tree

changelog.d/16150.misc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Clean-up calling `setup_background_tasks` in unit tests.
1+
Improve presence tests.

changelog.d/16151.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve presence tests.

tests/handlers/test_presence.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from synapse.rest import admin
3939
from synapse.rest.client import room
4040
from synapse.server import HomeServer
41+
from synapse.storage.database import LoggingDatabaseConnection
4142
from synapse.types import JsonDict, UserID, get_domain_from_id
4243
from synapse.util import Clock
4344

@@ -513,6 +514,121 @@ def test_last_active(self) -> None:
513514
self.assertEqual(state, new_state)
514515

515516

517+
class PresenceHandlerInitTestCase(unittest.HomeserverTestCase):
518+
def default_config(self) -> JsonDict:
519+
config = super().default_config()
520+
# Disable background tasks on this worker so that the PresenceHandler isn't
521+
# loaded until we request it.
522+
config["run_background_tasks_on"] = "other"
523+
return config
524+
525+
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
526+
self.user_id = f"@test:{self.hs.config.server.server_name}"
527+
528+
# Move the reactor to the initial time.
529+
self.reactor.advance(1000)
530+
now = self.clock.time_msec()
531+
532+
main_store = hs.get_datastores().main
533+
self.get_success(
534+
main_store.update_presence(
535+
[
536+
UserPresenceState(
537+
user_id=self.user_id,
538+
state=PresenceState.ONLINE,
539+
last_active_ts=now,
540+
last_federation_update_ts=now,
541+
last_user_sync_ts=now,
542+
status_msg=None,
543+
currently_active=True,
544+
)
545+
]
546+
)
547+
)
548+
549+
# Regenerate the preloaded presence information on PresenceStore.
550+
def refill_presence(db_conn: LoggingDatabaseConnection) -> None:
551+
main_store._presence_on_startup = main_store._get_active_presence(db_conn)
552+
553+
self.get_success(main_store.db_pool.runWithConnection(refill_presence))
554+
555+
def test_restored_presence_idles(self) -> None:
556+
"""The presence state restored from the database should not persist forever."""
557+
558+
# Get the handler (which kicks off a bunch of timers).
559+
presence_handler = self.hs.get_presence_handler()
560+
561+
# Assert the user is online.
562+
state = self.get_success(
563+
presence_handler.get_state(UserID.from_string(self.user_id))
564+
)
565+
self.assertEqual(state.state, PresenceState.ONLINE)
566+
567+
# Advance such that the user should timeout.
568+
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 1000)
569+
self.reactor.pump([5])
570+
571+
# Check that the user is now offline.
572+
state = self.get_success(
573+
presence_handler.get_state(UserID.from_string(self.user_id))
574+
)
575+
self.assertEqual(state.state, PresenceState.OFFLINE)
576+
577+
@parameterized.expand(
578+
[
579+
(PresenceState.BUSY, PresenceState.BUSY),
580+
(PresenceState.ONLINE, PresenceState.ONLINE),
581+
(PresenceState.UNAVAILABLE, PresenceState.UNAVAILABLE),
582+
# Offline syncs don't update the state.
583+
(PresenceState.OFFLINE, PresenceState.ONLINE),
584+
]
585+
)
586+
@unittest.override_config({"experimental_features": {"msc3026_enabled": True}})
587+
def test_restored_presence_online_after_sync(
588+
self, sync_state: str, expected_state: str
589+
) -> None:
590+
"""
591+
The presence state restored from the database should be overridden with sync after a timeout.
592+
593+
Args:
594+
sync_state: The presence state of the new sync.
595+
expected_state: The expected presence right after the sync.
596+
"""
597+
598+
# Get the handler (which kicks off a bunch of timers).
599+
presence_handler = self.hs.get_presence_handler()
600+
601+
# Assert the user is online, as restored.
602+
state = self.get_success(
603+
presence_handler.get_state(UserID.from_string(self.user_id))
604+
)
605+
self.assertEqual(state.state, PresenceState.ONLINE)
606+
607+
# Advance slightly and sync.
608+
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 1000 / 2)
609+
self.get_success(
610+
presence_handler.user_syncing(
611+
self.user_id, sync_state != PresenceState.OFFLINE, sync_state
612+
)
613+
)
614+
615+
# Assert the user is in the expected state.
616+
state = self.get_success(
617+
presence_handler.get_state(UserID.from_string(self.user_id))
618+
)
619+
self.assertEqual(state.state, expected_state)
620+
621+
# Advance such that the user's preloaded data times out, but not the new sync.
622+
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 1000 / 2)
623+
self.reactor.pump([5])
624+
625+
# Check that the user is in the sync state (as the client is currently syncing still).
626+
state = self.get_success(
627+
presence_handler.get_state(UserID.from_string(self.user_id))
628+
)
629+
self.assertEqual(state.state, sync_state)
630+
631+
516632
class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
517633
user_id = "@test:server"
518634
user_id_obj = UserID.from_string(user_id)

0 commit comments

Comments
 (0)