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

Fix an invalid comparison of UserPresenceState to str #14393

Merged
merged 9 commits into from
Nov 16, 2022
1 change: 1 addition & 0 deletions changelog.d/14393.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a bug introduced in 1.58.0 where a user with presence state 'org.matrix.msc3026.busy' would mistakenly be set to 'online' when calling `/sync` or `/events` on a worker process.
2 changes: 1 addition & 1 deletion synapse/handlers/presence.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ async def user_syncing(
return _NullContextManager()

prev_state = await self.current_state_for_user(user_id)
if prev_state != PresenceState.BUSY:
if prev_state.state != PresenceState.BUSY:
# We set state here but pass ignore_status_msg = True as we don't want to
# cause the status message to be cleared.
# Note that this causes last_active_ts to be incremented which is not
Expand Down
41 changes: 35 additions & 6 deletions tests/handlers/test_presence.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from typing import Optional
from unittest.mock import Mock, call

from parameterized import parameterized
from signedjson.key import generate_signing_key

from synapse.api.constants import EventTypes, Membership, PresenceState
Expand All @@ -37,6 +38,7 @@
from synapse.types import UserID, get_domain_from_id

from tests import unittest
from tests.replication._base import BaseMultiWorkerStreamTestCase


class PresenceUpdateTestCase(unittest.HomeserverTestCase):
Expand Down Expand Up @@ -505,7 +507,7 @@ def test_last_active(self):
self.assertEqual(state, new_state)


class PresenceHandlerTestCase(unittest.HomeserverTestCase):
class PresenceHandlerTestCase(BaseMultiWorkerStreamTestCase):
babolivier marked this conversation as resolved.
Show resolved Hide resolved
def prepare(self, reactor, clock, hs):
self.presence_handler = hs.get_presence_handler()
self.clock = hs.get_clock()
Expand Down Expand Up @@ -716,20 +718,47 @@ def test_set_presence_from_syncing_keeps_status(self):
# our status message should be the same as it was before
self.assertEqual(state.status_msg, status_msg)

def test_set_presence_from_syncing_keeps_busy(self):
"""Test that presence set by syncing doesn't affect busy status"""
# while this isn't the default
self.presence_handler._busy_presence_enabled = True
@parameterized.expand([(False,), (True,)])
@unittest.override_config(
{
"experimental_features": {
"msc3026_enabled": True,
},
}
)
def test_set_presence_from_syncing_keeps_busy(self, test_with_workers: bool):
"""Test that presence set by syncing doesn't affect busy status

Args:
test_with_workers: If True, check the presence state of the user by calling
/sync against a worker, rather than the main process.
"""
user_id = "@test:server"
status_msg = "I'm busy!"

# By default, we call /sync against the main process.
worker_to_sync_against = self.hs
if test_with_workers:
# Create a worker and use it to handle /sync traffic instead.
# This is used to test that presence changes get replicated from workers
# to the main process correctly.
worker_to_sync_against = self.make_worker_hs(
"synapse.app.generic_worker", {"worker_name": "presence_writer"}
)

# Set presence to BUSY
self._set_presencestate_with_status_msg(user_id, PresenceState.BUSY, status_msg)

# Perform a sync with a presence state other than busy. This should NOT change
# our presence status; we only change from busy if we explicitly set it via
# /presence/*.
self.get_success(
self.presence_handler.user_syncing(user_id, True, PresenceState.ONLINE)
worker_to_sync_against.get_presence_handler().user_syncing(
user_id, True, PresenceState.ONLINE
)
)

# Check against the main process that the user's presence did not change.
state = self.get_success(
self.presence_handler.get_state(UserID.from_string(user_id))
)
Expand Down
3 changes: 3 additions & 0 deletions tests/module_api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -778,8 +778,11 @@ def _test_sending_local_online_presence_to_local_user(
worker process. The test users will still sync with the main process. The purpose of testing
with a worker is to check whether a Synapse module running on a worker can inform other workers/
the main process that they should include additional presence when a user next syncs.
If this argument is True, `test_case` MUST be an instance of BaseMultiWorkerStreamTestCase.
"""
if test_with_workers:
assert isinstance(test_case, BaseMultiWorkerStreamTestCase)

# Create a worker process to make module_api calls against
worker_hs = test_case.make_worker_hs(
"synapse.app.generic_worker", {"worker_name": "presence_writer"}
Expand Down
7 changes: 6 additions & 1 deletion tests/replication/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,13 @@ def handle_command(self, command, *args):
self.send("OK")
elif command == b"GET":
self.send(None)

# Connection keep-alives.
elif command == b"PING":
self.send("PONG")

else:
raise Exception("Unknown command")
raise Exception(f"Unknown command: {command}")

def send(self, msg):
"""Send a message back to the client."""
Expand Down