mirror of
https://github.com/element-hq/synapse.git
synced 2026-07-11 18:29:25 +00:00
Make the presence state-machine timers configurable (#19942)
Adds `last_active_granularity`, `sync_online_timeout` and `idle_timeout` options to the `presence` config section, controlling the previously hard-coded `LAST_ACTIVE_GRANULARITY`, `SYNC_ONLINE_TIMEOUT` and `IDLE_TIMER` constants (which remain as the defaults). This is mainly useful on deployments that ratelimit how often syncs can affect presence (`rc_presence`): the sync timeout must exceed the ratelimit interval or users flap offline between syncs, so tuning down presence traffic currently requires squeezing under the fixed 30s limit. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Add `last_active_granularity`, `sync_online_timeout` and `idle_timeout` options to the `presence` config section to allow tuning the presence state machine timers.
|
||||
@@ -284,6 +284,24 @@ This setting has the following sub-options:
|
||||
|
||||
* `include_offline_users_on_sync` (boolean): When clients perform an initial or `full_state` sync, presence results for offline users are not included by default. Setting `include_offline_users_on_sync` to `true` will always include offline users in the results. Defaults to `false`.
|
||||
|
||||
* `last_active_granularity` (duration): How long after a user was last active that they are still shown as "currently active" to other users. Larger values reduce the rate of presence updates sent to other users and servers.
|
||||
|
||||
*Added in Synapse 1.156.0.*
|
||||
|
||||
Defaults to `"1m"`.
|
||||
|
||||
* `sync_online_timeout` (duration): How long after a client's last sync request their presence is switched to offline. Clients are expected to keep a sync request open at (almost) all times while online, so this only needs to cover the gap between two consecutive sync requests. Note that if `rc_presence` is set to ratelimit how often syncs can affect presence, this must be greater than the ratelimit's interval or users will incorrectly be marked as offline in between syncs.
|
||||
|
||||
*Added in Synapse 1.156.0.*
|
||||
|
||||
Defaults to `"30s"`.
|
||||
|
||||
* `idle_timeout` (duration): How long after a user was last active that their presence is switched to "unavailable" (idle) while they remain connected. Must be greater than `last_active_granularity`.
|
||||
|
||||
*Added in Synapse 1.156.0.*
|
||||
|
||||
Defaults to `"5m"`.
|
||||
|
||||
Example configuration:
|
||||
```yaml
|
||||
presence:
|
||||
|
||||
@@ -202,6 +202,46 @@ properties:
|
||||
`include_offline_users_on_sync` to `true` will always include offline
|
||||
users in the results.
|
||||
default: false
|
||||
last_active_granularity:
|
||||
$ref: "#/$defs/duration"
|
||||
description: >-
|
||||
How long after a user was last active that they are still shown as
|
||||
"currently active" to other users. Larger values reduce the rate of
|
||||
presence updates sent to other users and servers.
|
||||
|
||||
|
||||
*Added in Synapse 1.156.0.*
|
||||
default: 1m
|
||||
examples:
|
||||
- 5m
|
||||
sync_online_timeout:
|
||||
$ref: "#/$defs/duration"
|
||||
description: >-
|
||||
How long after a client's last sync request their presence is
|
||||
switched to offline. Clients are expected to keep a sync request
|
||||
open at (almost) all times while online, so this only needs to
|
||||
cover the gap between two consecutive sync requests. Note that if
|
||||
`rc_presence` is set to ratelimit how often syncs can affect
|
||||
presence, this must be greater than the ratelimit's interval or
|
||||
users will incorrectly be marked as offline in between syncs.
|
||||
|
||||
|
||||
*Added in Synapse 1.156.0.*
|
||||
default: 30s
|
||||
examples:
|
||||
- 1m
|
||||
idle_timeout:
|
||||
$ref: "#/$defs/duration"
|
||||
description: >-
|
||||
How long after a user was last active that their presence is
|
||||
switched to "unavailable" (idle) while they remain connected. Must
|
||||
be greater than `last_active_granularity`.
|
||||
|
||||
|
||||
*Added in Synapse 1.156.0.*
|
||||
default: 5m
|
||||
examples:
|
||||
- 10m
|
||||
examples:
|
||||
- enabled: false
|
||||
include_offline_users_on_sync: false
|
||||
|
||||
@@ -177,6 +177,19 @@ DEFAULT_IP_RANGE_BLOCKLIST = [
|
||||
|
||||
DEFAULT_ROOM_VERSION = "10"
|
||||
|
||||
# Defaults for the presence state machine timers, in milliseconds. Overridden
|
||||
# by the corresponding options in the `presence` config section.
|
||||
#
|
||||
# How long after a user was last active that they are still considered
|
||||
# "currently_active".
|
||||
DEFAULT_LAST_ACTIVE_GRANULARITY = 60 * 1000
|
||||
# How long to wait until a new /events or /sync request before assuming the
|
||||
# client has gone.
|
||||
DEFAULT_SYNC_ONLINE_TIMEOUT = 30 * 1000
|
||||
# How long to wait before marking the user as idle. Compared against last
|
||||
# active.
|
||||
DEFAULT_IDLE_TIMER = 5 * 60 * 1000
|
||||
|
||||
ROOM_COMPLEXITY_TOO_GREAT = (
|
||||
"Your homeserver is unable to join rooms this large or complex. "
|
||||
"Please speak to your server administrator, or upgrade your instance "
|
||||
@@ -505,6 +518,32 @@ class ServerConfig(Config):
|
||||
"include_offline_users_on_sync", False
|
||||
)
|
||||
|
||||
# Timers controlling the presence state machine.
|
||||
self.presence_last_active_granularity = self.parse_duration(
|
||||
presence_config.get(
|
||||
"last_active_granularity", DEFAULT_LAST_ACTIVE_GRANULARITY
|
||||
)
|
||||
)
|
||||
self.presence_sync_online_timeout = self.parse_duration(
|
||||
presence_config.get("sync_online_timeout", DEFAULT_SYNC_ONLINE_TIMEOUT)
|
||||
)
|
||||
self.presence_idle_timeout = self.parse_duration(
|
||||
presence_config.get("idle_timeout", DEFAULT_IDLE_TIMER)
|
||||
)
|
||||
if self.presence_last_active_granularity <= 0:
|
||||
raise ConfigError(
|
||||
"'presence.last_active_granularity' must be a positive duration"
|
||||
)
|
||||
if self.presence_sync_online_timeout <= 0:
|
||||
raise ConfigError(
|
||||
"'presence.sync_online_timeout' must be a positive duration"
|
||||
)
|
||||
if self.presence_idle_timeout <= self.presence_last_active_granularity:
|
||||
raise ConfigError(
|
||||
"'presence.idle_timeout' must be greater than "
|
||||
"'presence.last_active_granularity'"
|
||||
)
|
||||
|
||||
# Custom presence router module
|
||||
# This is the legacy way of configuring it (the config should now be put in the modules section)
|
||||
self.presence_router_module_class = None
|
||||
|
||||
@@ -179,19 +179,18 @@ presence_wheel_timer_size_gauge = LaterGauge(
|
||||
labelnames=[SERVER_NAME_LABEL],
|
||||
)
|
||||
|
||||
# If a user was last active in the last LAST_ACTIVE_GRANULARITY, consider them
|
||||
# "currently_active"
|
||||
LAST_ACTIVE_GRANULARITY = 60 * 1000
|
||||
# Note: the timers deciding when a user goes idle or offline and how long
|
||||
# they count as "currently_active" are configurable, via the
|
||||
# `last_active_granularity`, `sync_online_timeout` and `idle_timeout` options
|
||||
# in the `presence` config section (see
|
||||
# `synapse.config.server.DEFAULT_LAST_ACTIVE_GRANULARITY` and friends for the
|
||||
# defaults).
|
||||
|
||||
# How long to wait until a new /events or /sync request before assuming
|
||||
# the client has gone.
|
||||
SYNC_ONLINE_TIMEOUT = 30 * 1000
|
||||
# Busy status waits longer, but does eventually go offline.
|
||||
# How long to wait until a device with busy status stops syncing before it
|
||||
# goes offline. Busy status waits longer than the (configurable) sync online
|
||||
# timeout, but does eventually go offline.
|
||||
BUSY_ONLINE_TIMEOUT = 60 * 60 * 1000
|
||||
|
||||
# How long to wait before marking the user as idle. Compared against last active
|
||||
IDLE_TIMER = 5 * 60 * 1000
|
||||
|
||||
# How often we expect remote servers to resend us presence.
|
||||
FEDERATION_TIMEOUT = 30 * 60 * 1000
|
||||
|
||||
@@ -206,8 +205,6 @@ EXTERNAL_PROCESS_EXPIRY = 5 * 60 * 1000
|
||||
# syncing.
|
||||
UPDATE_SYNCING_USERS = Duration(seconds=10)
|
||||
|
||||
assert LAST_ACTIVE_GRANULARITY < IDLE_TIMER
|
||||
|
||||
|
||||
class BasePresenceHandler(abc.ABC):
|
||||
"""Parts of the PresenceHandler that are shared between workers and presence
|
||||
@@ -225,6 +222,13 @@ class BasePresenceHandler(abc.ABC):
|
||||
self._presence_enabled = hs.config.server.presence_enabled
|
||||
self._track_presence = hs.config.server.track_presence
|
||||
|
||||
# The (configurable) presence state machine timers.
|
||||
self._last_active_granularity = (
|
||||
hs.config.server.presence_last_active_granularity
|
||||
)
|
||||
self._sync_online_timeout = hs.config.server.presence_sync_online_timeout
|
||||
self._idle_timer = hs.config.server.presence_idle_timeout
|
||||
|
||||
self._federation = None
|
||||
if hs.should_send_federation():
|
||||
self._federation = hs.get_federation_sender()
|
||||
@@ -685,7 +689,11 @@ class WorkerPresenceHandler(BasePresenceHandler):
|
||||
self.user_to_current_state[new_state.user_id] = new_state
|
||||
is_mine = self.is_mine_id(new_state.user_id)
|
||||
if not old_state or should_notify(
|
||||
old_state, new_state, is_mine, self.server_name
|
||||
old_state,
|
||||
new_state,
|
||||
is_mine,
|
||||
self.server_name,
|
||||
last_active_granularity=self._last_active_granularity,
|
||||
):
|
||||
state_to_notify.append(new_state)
|
||||
|
||||
@@ -791,7 +799,8 @@ class PresenceHandler(BasePresenceHandler):
|
||||
if self._track_presence:
|
||||
for state in self.user_to_current_state.values():
|
||||
# Create a psuedo-device to properly handle time outs. This will
|
||||
# be overridden by any "real" devices within SYNC_ONLINE_TIMEOUT.
|
||||
# be overridden by any "real" devices within the sync online
|
||||
# timeout.
|
||||
pseudo_device_id = None
|
||||
self._user_to_device_to_current_state[state.user_id] = {
|
||||
pseudo_device_id: UserDevicePresenceState(
|
||||
@@ -804,12 +813,14 @@ class PresenceHandler(BasePresenceHandler):
|
||||
}
|
||||
|
||||
self.wheel_timer.insert(
|
||||
now=now, obj=state.user_id, then=state.last_active_ts + IDLE_TIMER
|
||||
now=now,
|
||||
obj=state.user_id,
|
||||
then=state.last_active_ts + self._idle_timer,
|
||||
)
|
||||
self.wheel_timer.insert(
|
||||
now=now,
|
||||
obj=state.user_id,
|
||||
then=state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
|
||||
then=state.last_user_sync_ts + self._sync_online_timeout,
|
||||
)
|
||||
if self.is_mine_id(state.user_id):
|
||||
self.wheel_timer.insert(
|
||||
@@ -996,6 +1007,9 @@ class PresenceHandler(BasePresenceHandler):
|
||||
# When overriding disabled presence, don't kick off all the
|
||||
# wheel timers.
|
||||
persist=not self._track_presence,
|
||||
idle_timer=self._idle_timer,
|
||||
sync_online_timeout=self._sync_online_timeout,
|
||||
last_active_granularity=self._last_active_granularity,
|
||||
)
|
||||
|
||||
if force_notify:
|
||||
@@ -1108,6 +1122,9 @@ class PresenceHandler(BasePresenceHandler):
|
||||
syncing_user_devices=syncing_user_devices,
|
||||
user_to_devices=self._user_to_device_to_current_state,
|
||||
now=now,
|
||||
idle_timer=self._idle_timer,
|
||||
sync_online_timeout=self._sync_online_timeout,
|
||||
last_active_granularity=self._last_active_granularity,
|
||||
)
|
||||
|
||||
return await self._update_states(changes)
|
||||
@@ -1695,6 +1712,8 @@ def should_notify(
|
||||
new_state: UserPresenceState,
|
||||
is_mine: bool,
|
||||
our_server_name: str,
|
||||
*,
|
||||
last_active_granularity: int,
|
||||
) -> bool:
|
||||
"""Decides if a presence state change should be sent to interested parties."""
|
||||
user_location = "remote"
|
||||
@@ -1741,7 +1760,7 @@ def should_notify(
|
||||
|
||||
if (
|
||||
new_state.last_active_ts - old_state.last_active_ts
|
||||
> LAST_ACTIVE_GRANULARITY
|
||||
> last_active_granularity
|
||||
):
|
||||
# Only notify about last active bumps if we're not currently active
|
||||
if not new_state.currently_active:
|
||||
@@ -1752,7 +1771,7 @@ def should_notify(
|
||||
).inc()
|
||||
return True
|
||||
|
||||
elif new_state.last_active_ts - old_state.last_active_ts > LAST_ACTIVE_GRANULARITY:
|
||||
elif new_state.last_active_ts - old_state.last_active_ts > last_active_granularity:
|
||||
# Always notify for a transition where last active gets bumped.
|
||||
notify_reason_counter.labels(
|
||||
locality=user_location,
|
||||
@@ -2075,6 +2094,10 @@ def handle_timeouts(
|
||||
syncing_user_devices: AbstractSet[tuple[str, str | None]],
|
||||
user_to_devices: dict[str, dict[str | None, UserDevicePresenceState]],
|
||||
now: int,
|
||||
*,
|
||||
idle_timer: int,
|
||||
sync_online_timeout: int,
|
||||
last_active_granularity: int,
|
||||
) -> list[UserPresenceState]:
|
||||
"""Checks the presence of users that have timed out and updates as
|
||||
appropriate.
|
||||
@@ -2085,6 +2108,11 @@ def handle_timeouts(
|
||||
syncing_user_devices: A set of (user ID, device ID) tuples with active syncs..
|
||||
user_to_devices: A map of user ID to device ID to UserDevicePresenceState.
|
||||
now: Current time in ms.
|
||||
idle_timer: How long in ms before an inactive device is marked as idle.
|
||||
sync_online_timeout: How long in ms after the last sync before a device
|
||||
is marked as offline.
|
||||
last_active_granularity: How long in ms a user counts as
|
||||
"currently active" after their last activity.
|
||||
|
||||
Returns:
|
||||
List of UserPresenceState updates
|
||||
@@ -2101,6 +2129,9 @@ def handle_timeouts(
|
||||
syncing_user_devices,
|
||||
user_to_devices.get(user_id, {}),
|
||||
now,
|
||||
idle_timer=idle_timer,
|
||||
sync_online_timeout=sync_online_timeout,
|
||||
last_active_granularity=last_active_granularity,
|
||||
)
|
||||
if new_state:
|
||||
changes[state.user_id] = new_state
|
||||
@@ -2114,6 +2145,10 @@ def handle_timeout(
|
||||
syncing_device_ids: AbstractSet[tuple[str, str | None]],
|
||||
user_devices: dict[str | None, UserDevicePresenceState],
|
||||
now: int,
|
||||
*,
|
||||
idle_timer: int,
|
||||
sync_online_timeout: int,
|
||||
last_active_granularity: int,
|
||||
) -> UserPresenceState | None:
|
||||
"""Checks the presence of the user to see if any of the timers have elapsed
|
||||
|
||||
@@ -2123,6 +2158,11 @@ def handle_timeout(
|
||||
syncing_user_devices: A set of (user ID, device ID) tuples with active syncs..
|
||||
user_devices: A map of device ID to UserDevicePresenceState.
|
||||
now: Current time in ms.
|
||||
idle_timer: How long in ms before an inactive device is marked as idle.
|
||||
sync_online_timeout: How long in ms after the last sync before a device
|
||||
is marked as offline.
|
||||
last_active_granularity: How long in ms a user counts as
|
||||
"currently active" after their last activity.
|
||||
|
||||
Returns:
|
||||
A UserPresenceState update or None if no update.
|
||||
@@ -2140,7 +2180,7 @@ def handle_timeout(
|
||||
offline_devices = []
|
||||
for device_id, device_state in user_devices.items():
|
||||
if device_state.state == PresenceState.ONLINE:
|
||||
if now - device_state.last_active_ts > IDLE_TIMER:
|
||||
if now - device_state.last_active_ts > idle_timer:
|
||||
# Currently online, but last activity ages ago so auto
|
||||
# idle
|
||||
device_state.state = PresenceState.UNAVAILABLE
|
||||
@@ -2161,7 +2201,7 @@ def handle_timeout(
|
||||
online_timeout = (
|
||||
BUSY_ONLINE_TIMEOUT
|
||||
if device_state.state == PresenceState.BUSY
|
||||
else SYNC_ONLINE_TIMEOUT
|
||||
else sync_online_timeout
|
||||
)
|
||||
if now - sync_or_active > online_timeout:
|
||||
# Mark the device as going offline.
|
||||
@@ -2180,7 +2220,7 @@ def handle_timeout(
|
||||
state = state.copy_and_replace(state=new_presence)
|
||||
changed = True
|
||||
|
||||
if now - state.last_active_ts > LAST_ACTIVE_GRANULARITY:
|
||||
if now - state.last_active_ts > last_active_granularity:
|
||||
# So that we send down a notification that we've
|
||||
# stopped updating.
|
||||
changed = True
|
||||
@@ -2209,6 +2249,10 @@ def handle_update(
|
||||
wheel_timer: WheelTimer,
|
||||
now: int,
|
||||
persist: bool,
|
||||
*,
|
||||
idle_timer: int,
|
||||
sync_online_timeout: int,
|
||||
last_active_granularity: int,
|
||||
) -> tuple[UserPresenceState, bool, bool]:
|
||||
"""Given a presence update:
|
||||
1. Add any appropriate timers.
|
||||
@@ -2223,6 +2267,11 @@ def handle_update(
|
||||
now: Time now in ms
|
||||
persist: True if this state should persist until another update occurs.
|
||||
Skips insertion into wheel timers.
|
||||
idle_timer: How long in ms before an inactive device is marked as idle.
|
||||
sync_online_timeout: How long in ms after the last sync before a device
|
||||
is marked as offline.
|
||||
last_active_granularity: How long in ms a user counts as
|
||||
"currently active" after their last activity.
|
||||
|
||||
Returns:
|
||||
3-tuple: `(new_state, persist_and_notify, federation_ping)` where:
|
||||
@@ -2242,17 +2291,17 @@ def handle_update(
|
||||
# Idle timer
|
||||
if not persist:
|
||||
wheel_timer.insert(
|
||||
now=now, obj=user_id, then=new_state.last_active_ts + IDLE_TIMER
|
||||
now=now, obj=user_id, then=new_state.last_active_ts + idle_timer
|
||||
)
|
||||
|
||||
active = now - new_state.last_active_ts < LAST_ACTIVE_GRANULARITY
|
||||
active = now - new_state.last_active_ts < last_active_granularity
|
||||
new_state = new_state.copy_and_replace(currently_active=active)
|
||||
|
||||
if active and not persist:
|
||||
wheel_timer.insert(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_active_ts + LAST_ACTIVE_GRANULARITY,
|
||||
then=new_state.last_active_ts + last_active_granularity,
|
||||
)
|
||||
|
||||
if new_state.state != PresenceState.OFFLINE:
|
||||
@@ -2261,7 +2310,7 @@ def handle_update(
|
||||
wheel_timer.insert(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
|
||||
then=new_state.last_user_sync_ts + sync_online_timeout,
|
||||
)
|
||||
|
||||
last_federate = new_state.last_federation_update_ts
|
||||
@@ -2287,7 +2336,13 @@ def handle_update(
|
||||
)
|
||||
|
||||
# Check whether the change was something worth notifying about
|
||||
if should_notify(prev_state, new_state, is_mine, our_server_name):
|
||||
if should_notify(
|
||||
prev_state,
|
||||
new_state,
|
||||
is_mine,
|
||||
our_server_name,
|
||||
last_active_granularity=last_active_granularity,
|
||||
):
|
||||
new_state = new_state.copy_and_replace(last_federation_update_ts=now)
|
||||
persist_and_notify = True
|
||||
|
||||
|
||||
+222
-37
@@ -36,6 +36,11 @@ from synapse.api.presence import UserDevicePresenceState, UserPresenceState
|
||||
from synapse.api.room_versions import (
|
||||
RoomVersion,
|
||||
)
|
||||
from synapse.config.server import (
|
||||
DEFAULT_IDLE_TIMER,
|
||||
DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
)
|
||||
from synapse.crypto.event_signing import add_hashes_and_signatures
|
||||
from synapse.events import EventBase, make_event_from_dict
|
||||
from synapse.federation.sender import FederationSender
|
||||
@@ -44,9 +49,6 @@ from synapse.handlers.presence import (
|
||||
EXTERNAL_PROCESS_EXPIRY,
|
||||
FEDERATION_PING_INTERVAL,
|
||||
FEDERATION_TIMEOUT,
|
||||
IDLE_TIMER,
|
||||
LAST_ACTIVE_GRANULARITY,
|
||||
SYNC_ONLINE_TIMEOUT,
|
||||
PresenceHandler,
|
||||
handle_timeout,
|
||||
handle_update,
|
||||
@@ -94,6 +96,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertTrue(persist_and_notify)
|
||||
@@ -105,16 +110,20 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(wheel_timer.insert.call_count, 3)
|
||||
wheel_timer.insert.assert_has_calls(
|
||||
[
|
||||
call(now=now, obj=user_id, then=new_state.last_active_ts + IDLE_TIMER),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
|
||||
then=new_state.last_active_ts + DEFAULT_IDLE_TIMER,
|
||||
),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_active_ts + LAST_ACTIVE_GRANULARITY,
|
||||
then=new_state.last_user_sync_ts + DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_active_ts + DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
),
|
||||
],
|
||||
any_order=True,
|
||||
@@ -142,6 +151,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertFalse(persist_and_notify)
|
||||
@@ -154,16 +166,20 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(wheel_timer.insert.call_count, 3)
|
||||
wheel_timer.insert.assert_has_calls(
|
||||
[
|
||||
call(now=now, obj=user_id, then=new_state.last_active_ts + IDLE_TIMER),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
|
||||
then=new_state.last_active_ts + DEFAULT_IDLE_TIMER,
|
||||
),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_active_ts + LAST_ACTIVE_GRANULARITY,
|
||||
then=new_state.last_user_sync_ts + DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_active_ts + DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
),
|
||||
],
|
||||
any_order=True,
|
||||
@@ -177,7 +193,7 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
prev_state = UserPresenceState.default(user_id)
|
||||
prev_state = prev_state.copy_and_replace(
|
||||
state=PresenceState.ONLINE,
|
||||
last_active_ts=now - LAST_ACTIVE_GRANULARITY - 10,
|
||||
last_active_ts=now - DEFAULT_LAST_ACTIVE_GRANULARITY - 10,
|
||||
currently_active=True,
|
||||
)
|
||||
|
||||
@@ -193,6 +209,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertFalse(persist_and_notify)
|
||||
@@ -205,16 +224,20 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(wheel_timer.insert.call_count, 3)
|
||||
wheel_timer.insert.assert_has_calls(
|
||||
[
|
||||
call(now=now, obj=user_id, then=new_state.last_active_ts + IDLE_TIMER),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
|
||||
then=new_state.last_active_ts + DEFAULT_IDLE_TIMER,
|
||||
),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_active_ts + LAST_ACTIVE_GRANULARITY,
|
||||
then=new_state.last_user_sync_ts + DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_active_ts + DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
),
|
||||
],
|
||||
any_order=True,
|
||||
@@ -228,7 +251,7 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
prev_state = UserPresenceState.default(user_id)
|
||||
prev_state = prev_state.copy_and_replace(
|
||||
state=PresenceState.ONLINE,
|
||||
last_active_ts=now - LAST_ACTIVE_GRANULARITY - 1,
|
||||
last_active_ts=now - DEFAULT_LAST_ACTIVE_GRANULARITY - 1,
|
||||
currently_active=True,
|
||||
)
|
||||
|
||||
@@ -242,6 +265,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertTrue(persist_and_notify)
|
||||
@@ -253,11 +279,15 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(wheel_timer.insert.call_count, 2)
|
||||
wheel_timer.insert.assert_has_calls(
|
||||
[
|
||||
call(now=now, obj=user_id, then=new_state.last_active_ts + IDLE_TIMER),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
|
||||
then=new_state.last_active_ts + DEFAULT_IDLE_TIMER,
|
||||
),
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_user_sync_ts + DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
),
|
||||
],
|
||||
any_order=True,
|
||||
@@ -283,6 +313,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertFalse(persist_and_notify)
|
||||
@@ -323,6 +356,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertTrue(persist_and_notify)
|
||||
@@ -351,6 +387,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertTrue(persist_and_notify)
|
||||
@@ -365,7 +404,7 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
call(
|
||||
now=now,
|
||||
obj=user_id,
|
||||
then=new_state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
|
||||
then=new_state.last_user_sync_ts + DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
)
|
||||
],
|
||||
any_order=True,
|
||||
@@ -442,6 +481,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=True,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
wheel_timer.insert.assert_not_called()
|
||||
@@ -506,6 +548,9 @@ class PresenceUpdateTestCase(unittest.HomeserverTestCase):
|
||||
wheel_timer=wheel_timer,
|
||||
now=now,
|
||||
persist=False,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
# Check that the user is offline.
|
||||
@@ -556,7 +601,7 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
state = UserPresenceState.default(user_id)
|
||||
state = state.copy_and_replace(
|
||||
state=PresenceState.ONLINE,
|
||||
last_active_ts=now - IDLE_TIMER - 1,
|
||||
last_active_ts=now - DEFAULT_IDLE_TIMER - 1,
|
||||
last_user_sync_ts=now,
|
||||
status_msg=status_msg,
|
||||
)
|
||||
@@ -574,6 +619,9 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
syncing_device_ids=set(),
|
||||
user_devices={device_id: device_state},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(new_state)
|
||||
@@ -594,7 +642,7 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
state = UserPresenceState.default(user_id)
|
||||
state = state.copy_and_replace(
|
||||
state=PresenceState.BUSY,
|
||||
last_active_ts=now - IDLE_TIMER - 1,
|
||||
last_active_ts=now - DEFAULT_IDLE_TIMER - 1,
|
||||
last_user_sync_ts=now,
|
||||
status_msg=status_msg,
|
||||
)
|
||||
@@ -612,6 +660,9 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
syncing_device_ids=set(),
|
||||
user_devices={device_id: device_state},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(new_state)
|
||||
@@ -629,7 +680,7 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
state = state.copy_and_replace(
|
||||
state=PresenceState.ONLINE,
|
||||
last_active_ts=0,
|
||||
last_user_sync_ts=now - SYNC_ONLINE_TIMEOUT - 1,
|
||||
last_user_sync_ts=now - DEFAULT_SYNC_ONLINE_TIMEOUT - 1,
|
||||
status_msg=status_msg,
|
||||
)
|
||||
device_state = UserDevicePresenceState(
|
||||
@@ -646,6 +697,9 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
syncing_device_ids=set(),
|
||||
user_devices={device_id: device_state},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(new_state)
|
||||
@@ -662,8 +716,8 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
state = UserPresenceState.default(user_id)
|
||||
state = state.copy_and_replace(
|
||||
state=PresenceState.ONLINE,
|
||||
last_active_ts=now - SYNC_ONLINE_TIMEOUT - 1,
|
||||
last_user_sync_ts=now - SYNC_ONLINE_TIMEOUT - 1,
|
||||
last_active_ts=now - DEFAULT_SYNC_ONLINE_TIMEOUT - 1,
|
||||
last_user_sync_ts=now - DEFAULT_SYNC_ONLINE_TIMEOUT - 1,
|
||||
status_msg=status_msg,
|
||||
)
|
||||
device_state = UserDevicePresenceState(
|
||||
@@ -680,6 +734,9 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
syncing_device_ids={(user_id, device_id)},
|
||||
user_devices={device_id: device_state},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(new_state)
|
||||
@@ -715,6 +772,9 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
syncing_device_ids=set(),
|
||||
user_devices={device_id: device_state},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(new_state)
|
||||
@@ -746,6 +806,9 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
syncing_device_ids=set(),
|
||||
user_devices={device_id: device_state},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNone(new_state)
|
||||
@@ -766,7 +829,14 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
|
||||
# Note that this is a remote user so we do not have their device information.
|
||||
new_state = handle_timeout(
|
||||
state, is_mine=False, syncing_device_ids=set(), user_devices={}, now=now
|
||||
state,
|
||||
is_mine=False,
|
||||
syncing_device_ids=set(),
|
||||
user_devices={},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(new_state)
|
||||
@@ -783,7 +853,7 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
state = UserPresenceState.default(user_id)
|
||||
state = state.copy_and_replace(
|
||||
state=PresenceState.ONLINE,
|
||||
last_active_ts=now - LAST_ACTIVE_GRANULARITY - 1,
|
||||
last_active_ts=now - DEFAULT_LAST_ACTIVE_GRANULARITY - 1,
|
||||
last_user_sync_ts=now,
|
||||
last_federation_update_ts=now,
|
||||
status_msg=status_msg,
|
||||
@@ -802,6 +872,9 @@ class PresenceTimeoutTestCase(unittest.TestCase):
|
||||
syncing_device_ids=set(),
|
||||
user_devices={device_id: device_state},
|
||||
now=now,
|
||||
idle_timer=DEFAULT_IDLE_TIMER,
|
||||
sync_online_timeout=DEFAULT_SYNC_ONLINE_TIMEOUT,
|
||||
last_active_granularity=DEFAULT_LAST_ACTIVE_GRANULARITY,
|
||||
)
|
||||
|
||||
self.assertIsNotNone(new_state)
|
||||
@@ -860,7 +933,7 @@ class PresenceHandlerInitTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(state.state, PresenceState.ONLINE)
|
||||
|
||||
# Advance such that the user should timeout.
|
||||
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 1000)
|
||||
self.reactor.advance(DEFAULT_SYNC_ONLINE_TIMEOUT / 1000)
|
||||
self.reactor.pump([5])
|
||||
|
||||
# Check that the user is now offline.
|
||||
@@ -900,7 +973,7 @@ class PresenceHandlerInitTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(state.state, PresenceState.ONLINE)
|
||||
|
||||
# Advance slightly and sync.
|
||||
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 1000 / 2)
|
||||
self.reactor.advance(DEFAULT_SYNC_ONLINE_TIMEOUT / 1000 / 2)
|
||||
self.get_success(
|
||||
presence_handler.user_syncing(
|
||||
self.user_id,
|
||||
@@ -917,7 +990,7 @@ class PresenceHandlerInitTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(state.state, expected_state)
|
||||
|
||||
# Advance such that the user's preloaded data times out, but not the new sync.
|
||||
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 1000 / 2)
|
||||
self.reactor.advance(DEFAULT_SYNC_ONLINE_TIMEOUT / 1000 / 2)
|
||||
self.reactor.pump([5])
|
||||
|
||||
# Check that the user is in the sync state (as the client is currently syncing still).
|
||||
@@ -927,6 +1000,118 @@ class PresenceHandlerInitTestCase(unittest.HomeserverTestCase):
|
||||
self.assertEqual(state.state, sync_state)
|
||||
|
||||
|
||||
# Timer values used by `PresenceConfigurableTimersTestCase`, all larger than
|
||||
# the corresponding defaults.
|
||||
_CUSTOM_TIMERS_CONFIG = {
|
||||
"presence": {
|
||||
"last_active_granularity": "2m",
|
||||
"sync_online_timeout": "3m",
|
||||
"idle_timeout": "20m",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PresenceConfigurableTimersTestCase(unittest.HomeserverTestCase):
|
||||
"""Tests that the presence state machine timers can be changed via the
|
||||
`presence` config section.
|
||||
|
||||
Each test checks that nothing happens where the default timer would have
|
||||
fired, and that the transition then occurs once the configured timer
|
||||
elapses.
|
||||
"""
|
||||
|
||||
device_id = "dev-1"
|
||||
|
||||
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
|
||||
self.presence_handler = hs.get_presence_handler()
|
||||
self.user_id = f"@test:{hs.config.server.server_name}"
|
||||
self.user_id_obj = UserID.from_string(self.user_id)
|
||||
|
||||
def _get_state(self) -> UserPresenceState:
|
||||
return self.get_success(self.presence_handler.get_state(self.user_id_obj))
|
||||
|
||||
@override_config(_CUSTOM_TIMERS_CONFIG)
|
||||
def test_config_parsing(self) -> None:
|
||||
config = self.hs.config.server
|
||||
self.assertEqual(config.presence_last_active_granularity, 2 * 60 * 1000)
|
||||
self.assertEqual(config.presence_sync_online_timeout, 3 * 60 * 1000)
|
||||
self.assertEqual(config.presence_idle_timeout, 20 * 60 * 1000)
|
||||
|
||||
@override_config(_CUSTOM_TIMERS_CONFIG)
|
||||
def test_sync_online_timeout(self) -> None:
|
||||
"""A user only goes offline once the configured sync timeout passes."""
|
||||
with self.get_success(
|
||||
self.presence_handler.user_syncing(
|
||||
self.user_id, self.device_id, True, PresenceState.ONLINE
|
||||
)
|
||||
):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._get_state().state, PresenceState.ONLINE)
|
||||
|
||||
# Well past the DEFAULT_SYNC_ONLINE_TIMEOUT, but short of the
|
||||
# configured 3m: still online.
|
||||
self.reactor.advance(2 * DEFAULT_SYNC_ONLINE_TIMEOUT / 1000)
|
||||
self.reactor.pump([5])
|
||||
self.assertEqual(self._get_state().state, PresenceState.ONLINE)
|
||||
|
||||
# Past the configured timeout: offline.
|
||||
self.reactor.advance(3 * 60)
|
||||
self.reactor.pump([5])
|
||||
self.assertEqual(self._get_state().state, PresenceState.OFFLINE)
|
||||
|
||||
@override_config(_CUSTOM_TIMERS_CONFIG)
|
||||
def test_idle_timeout(self) -> None:
|
||||
"""A continuously syncing but inactive user only goes idle once the
|
||||
configured idle timeout passes."""
|
||||
# Leave the sync open so the device never times out.
|
||||
self.get_success(
|
||||
self.presence_handler.user_syncing(
|
||||
self.user_id, self.device_id, True, PresenceState.ONLINE
|
||||
)
|
||||
)
|
||||
|
||||
# Well past the DEFAULT_IDLE_TIMER, but short of the configured 20m:
|
||||
# still online.
|
||||
self.reactor.advance(2 * DEFAULT_IDLE_TIMER / 1000)
|
||||
self.reactor.pump([5])
|
||||
self.assertEqual(self._get_state().state, PresenceState.ONLINE)
|
||||
|
||||
# Past the configured timeout: idle.
|
||||
self.reactor.advance(15 * 60)
|
||||
self.reactor.pump([5])
|
||||
self.assertEqual(self._get_state().state, PresenceState.UNAVAILABLE)
|
||||
|
||||
@override_config(_CUSTOM_TIMERS_CONFIG)
|
||||
def test_last_active_granularity(self) -> None:
|
||||
"""A user remains "currently active" for the configured duration
|
||||
after their last activity."""
|
||||
with self.get_success(
|
||||
self.presence_handler.user_syncing(
|
||||
self.user_id, self.device_id, True, PresenceState.ONLINE
|
||||
)
|
||||
):
|
||||
pass
|
||||
|
||||
self.assertTrue(self._get_state().currently_active)
|
||||
|
||||
# Past the DEFAULT_LAST_ACTIVE_GRANULARITY, but short of the
|
||||
# configured 2m: still currently active.
|
||||
self.reactor.advance(90)
|
||||
self.reactor.pump([5])
|
||||
state = self._get_state()
|
||||
self.assertEqual(state.state, PresenceState.ONLINE)
|
||||
self.assertTrue(state.currently_active)
|
||||
|
||||
# Past the configured granularity (but short of the 3m sync timeout):
|
||||
# no longer currently active, but still online.
|
||||
self.reactor.advance(60)
|
||||
self.reactor.pump([5])
|
||||
state = self._get_state()
|
||||
self.assertEqual(state.state, PresenceState.ONLINE)
|
||||
self.assertFalse(state.currently_active)
|
||||
|
||||
|
||||
class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
user_id = "@test:server"
|
||||
user_id_obj = UserID.from_string(user_id)
|
||||
@@ -979,14 +1164,14 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
|
||||
# Check that if we wait a while without telling the handler the user has
|
||||
# stopped syncing that their presence state doesn't get timed out.
|
||||
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 2)
|
||||
self.reactor.advance(DEFAULT_SYNC_ONLINE_TIMEOUT / 2)
|
||||
|
||||
state = self.get_success(self.presence_handler.get_state(self.user_id_obj))
|
||||
self.assertEqual(state.state, PresenceState.ONLINE)
|
||||
self.assertEqual(state.status_msg, status_msg)
|
||||
|
||||
# Check that if the timeout fires, then the syncing user gets timed out
|
||||
self.reactor.advance(SYNC_ONLINE_TIMEOUT)
|
||||
self.reactor.advance(DEFAULT_SYNC_ONLINE_TIMEOUT)
|
||||
|
||||
state = self.get_success(self.presence_handler.get_state(self.user_id_obj))
|
||||
# status_msg should remain even after going offline
|
||||
@@ -1273,7 +1458,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
)
|
||||
|
||||
# 2. Wait half the idle timer.
|
||||
self.reactor.advance(IDLE_TIMER / 1000 / 2)
|
||||
self.reactor.advance(DEFAULT_IDLE_TIMER / 1000 / 2)
|
||||
self.reactor.pump([0.1])
|
||||
|
||||
# 3. Sync with the second device.
|
||||
@@ -1300,7 +1485,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
# When testing with workers, make another random sync (with any *different*
|
||||
# user) to keep the process information from expiring.
|
||||
#
|
||||
# This is due to EXTERNAL_PROCESS_EXPIRY being equivalent to IDLE_TIMER.
|
||||
# This is due to EXTERNAL_PROCESS_EXPIRY being equivalent to DEFAULT_IDLE_TIMER.
|
||||
if test_with_workers:
|
||||
with self.get_success(
|
||||
worker_presence_handler.user_syncing(
|
||||
@@ -1314,7 +1499,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
|
||||
# 5. Advance such that the first device should be discarded (the idle timer),
|
||||
# then pump so _handle_timeouts function to called.
|
||||
self.reactor.advance(IDLE_TIMER / 1000 / 2)
|
||||
self.reactor.advance(DEFAULT_IDLE_TIMER / 1000 / 2)
|
||||
self.reactor.pump([0.01])
|
||||
|
||||
# 6. Assert the expected presence state.
|
||||
@@ -1330,7 +1515,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
|
||||
# 7. Advance such that the second device should be discarded (half the idle timer),
|
||||
# then pump so _handle_timeouts function to called.
|
||||
self.reactor.advance(IDLE_TIMER / 1000 / 2)
|
||||
self.reactor.advance(DEFAULT_IDLE_TIMER / 1000 / 2)
|
||||
self.reactor.pump([0.1])
|
||||
|
||||
# 8. The devices are still "syncing" (the sync context managers were never
|
||||
@@ -1533,7 +1718,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
|
||||
# 5. Advance such that the first device should be discarded (the sync timeout),
|
||||
# then pump so _handle_timeouts function to called.
|
||||
self.reactor.advance(SYNC_ONLINE_TIMEOUT / 1000)
|
||||
self.reactor.advance(DEFAULT_SYNC_ONLINE_TIMEOUT / 1000)
|
||||
self.reactor.pump([5])
|
||||
|
||||
# 6. Assert the expected presence state.
|
||||
@@ -1556,7 +1741,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
if dev_1_state == PresenceState.BUSY or dev_2_state == PresenceState.BUSY:
|
||||
timeout = BUSY_ONLINE_TIMEOUT
|
||||
else:
|
||||
timeout = SYNC_ONLINE_TIMEOUT
|
||||
timeout = DEFAULT_SYNC_ONLINE_TIMEOUT
|
||||
self.reactor.advance(timeout / 1000)
|
||||
self.reactor.pump([5])
|
||||
|
||||
@@ -1629,7 +1814,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
|
||||
# Advance such that the device would be discarded if it was not busy,
|
||||
# then pump so _handle_timeouts function to called.
|
||||
self.reactor.advance(IDLE_TIMER / 1000)
|
||||
self.reactor.advance(DEFAULT_IDLE_TIMER / 1000)
|
||||
self.reactor.pump([5])
|
||||
|
||||
# The account should still be busy.
|
||||
@@ -1682,7 +1867,7 @@ class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
|
||||
self.assertEqual(state.state, PresenceState.ONLINE)
|
||||
|
||||
# The timeout should not fire and the state should be the same.
|
||||
self.reactor.advance(SYNC_ONLINE_TIMEOUT)
|
||||
self.reactor.advance(DEFAULT_SYNC_ONLINE_TIMEOUT)
|
||||
state = self.get_success(self.presence_handler.get_state(self.user_id_obj))
|
||||
self.assertEqual(state.state, PresenceState.ONLINE)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user