Newer
Older
Matthew Hodgson
committed
# Copyright 2014 OpenMarket Ltd
Matthew Hodgson
committed
#
# 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.
Paul "LeoNerd" Evans
committed
from tests import unittest
Paul "LeoNerd" Evans
committed
from twisted.internet import defer, reactor
from mock import Mock, call, ANY, NonCallableMock
Paul "LeoNerd" Evans
committed
import json
Paul "LeoNerd" Evans
committed
from tests.utils import (
MockHttpResource, MockClock, DeferredMockCallable, setup_test_homeserver
Paul "LeoNerd" Evans
committed
)
Paul "LeoNerd" Evans
committed
from synapse.api.constants import PresenceState
from synapse.api.errors import SynapseError
from synapse.handlers.presence import PresenceHandler, UserPresenceCache
Paul "LeoNerd" Evans
committed
from synapse.streams.config import SourcePaginationConfig
Matthew Hodgson
committed
from synapse.storage.transactions import DestinationsTable
from synapse.types import UserID
Paul "LeoNerd" Evans
committed
UNAVAILABLE = PresenceState.UNAVAILABLE
Paul "LeoNerd" Evans
committed
def _expect_edu(destination, edu_type, content, origin="test"):
return {
"origin": origin,
Paul "LeoNerd" Evans
committed
"pdus": [],
"edus": [
{
"edu_type": edu_type,
"content": content,
}
],
Paul "LeoNerd" Evans
committed
}
Paul "LeoNerd" Evans
committed
def _make_edu_json(origin, edu_type, content):
return json.dumps(_expect_edu("test", edu_type, content, origin=origin))
class JustPresenceHandlers(object):
def __init__(self, hs):
self.presence_handler = PresenceHandler(hs)
Paul "LeoNerd" Evans
committed
class PresenceTestCase(unittest.TestCase):
Paul "LeoNerd" Evans
committed
@defer.inlineCallbacks
Paul "LeoNerd" Evans
committed
self.clock = MockClock()
self.mock_federation_resource = MockHttpResource()
self.mock_http_client = Mock(spec=[])
self.mock_http_client.put_json = DeferredMockCallable()
hs_kwargs = {}
if hasattr(self, "make_datastore_mock"):
hs_kwargs["datastore"] = self.make_datastore_mock()
hs = yield setup_test_homeserver(
Paul "LeoNerd" Evans
committed
clock=self.clock,
Paul "LeoNerd" Evans
committed
handlers=None,
Paul "LeoNerd" Evans
committed
resource_for_federation=self.mock_federation_resource,
http_client=self.mock_http_client,
**hs_kwargs
Paul "LeoNerd" Evans
committed
)
self.datastore = hs.get_datastore()
Paul "LeoNerd" Evans
committed
self.setUp_roommemberhandler_mocks(hs.handlers)
Paul "LeoNerd" Evans
committed
self.handler = hs.get_handlers().presence_handler
self.event_source = hs.get_event_sources().sources["presence"]
Paul "LeoNerd" Evans
committed
self.distributor = hs.get_distributor()
self.distributor.declare("user_joined_room")
Paul "LeoNerd" Evans
committed
yield self.setUp_users(hs)
def setUp_roommemberhandler_mocks(self, handlers):
self.room_id = "a-room"
self.room_members = []
room_member_handler = handlers.room_member_handler = Mock(spec=[
"get_room_members",
"fetch_room_distributions_into",
])
self.room_member_handler = room_member_handler
def get_rooms_for_user(user):
if user in self.room_members:
return defer.succeed([self.room_id])
else:
return defer.succeed([])
room_member_handler.get_joined_rooms_for_user = get_rooms_for_user
def get_room_members(room_id):
if room_id == self.room_id:
return defer.succeed(self.room_members)
else:
return defer.succeed([])
room_member_handler.get_room_members = get_room_members
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
@defer.inlineCallbacks
def fetch_room_distributions_into(room_id, localusers=None,
remotedomains=None, ignore_user=None):
members = yield get_room_members(room_id)
for member in members:
if ignore_user is not None and member == ignore_user:
continue
if member.is_mine:
if localusers is not None:
localusers.add(member)
else:
if remotedomains is not None:
remotedomains.add(member.domain)
room_member_handler.fetch_room_distributions_into = (
fetch_room_distributions_into)
self.setUp_datastore_room_mocks(self.datastore)
def setUp_datastore_room_mocks(self, datastore):
def get_room_hosts(room_id):
if room_id == self.room_id:
hosts = set([u.domain for u in self.room_members])
return defer.succeed(hosts)
else:
return defer.succeed([])
datastore.get_joined_hosts_for_room = get_room_hosts
Paul "LeoNerd" Evans
committed
def user_rooms_intersect(userlist):
Paul "LeoNerd" Evans
committed
room_member_ids = map(lambda u: u.to_string(), self.room_members)
shared = all(map(lambda i: i in room_member_ids, userlist))
Paul "LeoNerd" Evans
committed
return defer.succeed(shared)
datastore.user_rooms_intersect = user_rooms_intersect
Paul "LeoNerd" Evans
committed
@defer.inlineCallbacks
def setUp_users(self, hs):
# Some local users to test with
self.u_apple = UserID.from_string("@apple:test")
self.u_banana = UserID.from_string("@banana:test")
self.u_clementine = UserID.from_string("@clementine:test")
for u in self.u_apple, self.u_banana, self.u_clementine:
yield self.datastore.create_presence(u.localpart)
yield self.datastore.set_presence_state(
self.u_apple.localpart, {"state": ONLINE, "status_msg": "Online"}
)
# ID of a local user that does not exist
self.u_durian = UserID.from_string("@durian:test")
# A remote user
self.u_cabbage = UserID.from_string("@cabbage:elsewhere")
Paul "LeoNerd" Evans
committed
class MockedDatastorePresenceTestCase(PresenceTestCase):
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
def make_datastore_mock(self):
datastore = Mock(spec=[
# Bits that Federation needs
"prep_send_transaction",
"delivered_txn",
"get_received_txn_response",
"set_received_txn_response",
"get_destination_retry_timings",
])
self.setUp_datastore_federation_mocks(datastore)
self.setUp_datastore_presence_mocks(datastore)
return datastore
def setUp_datastore_federation_mocks(self, datastore):
datastore.get_destination_retry_timings.return_value = (
defer.succeed(DestinationsTable.EntryType("", 0, 0))
)
def get_received_txn_response(*args):
return defer.succeed(None)
datastore.get_received_txn_response = get_received_txn_response
def setUp_datastore_presence_mocks(self, datastore):
self.current_user_state = {
"apple": OFFLINE,
"banana": OFFLINE,
"clementine": OFFLINE,
"fig": OFFLINE,
}
def get_presence_state(user_localpart):
return defer.succeed(
{"state": self.current_user_state[user_localpart],
"status_msg": None,
"mtime": 123456000}
)
datastore.get_presence_state = get_presence_state
def set_presence_state(user_localpart, new_state):
was = self.current_user_state[user_localpart]
self.current_user_state[user_localpart] = new_state["state"]
return defer.succeed({"state": was})
datastore.set_presence_state = set_presence_state
def get_presence_list(user_localpart, accepted):
if not user_localpart in self.PRESENCE_LIST:
return defer.succeed([])
return defer.succeed([
{"observed_user_id": u} for u in
self.PRESENCE_LIST[user_localpart]])
datastore.get_presence_list = get_presence_list
def is_presence_visible(observed_localpart, observer_userid):
return True
datastore.is_presence_visible = is_presence_visible
@defer.inlineCallbacks
def setUp_users(self, hs):
# Some local users to test with
self.u_apple = UserID.from_string("@apple:test")
self.u_banana = UserID.from_string("@banana:test")
self.u_clementine = UserID.from_string("@clementine:test")
self.u_durian = UserID.from_string("@durian:test")
self.u_elderberry = UserID.from_string("@elderberry:test")
self.u_fig = UserID.from_string("@fig:test")
# Remote user
self.u_onion = UserID.from_string("@onion:farm")
self.u_potato = UserID.from_string("@potato:remote")
yield
Paul "LeoNerd" Evans
committed
class PresenceStateTestCase(PresenceTestCase):
""" Tests presence management. """
@defer.inlineCallbacks
def setUp(self):
yield super(PresenceStateTestCase, self).setUp()
self.mock_start = Mock()
self.mock_stop = Mock()
self.handler.start_polling_presence = self.mock_start
self.handler.stop_polling_presence = self.mock_stop
Paul "LeoNerd" Evans
committed
@defer.inlineCallbacks
def test_get_my_state(self):
state = yield self.handler.get_state(
target_user=self.u_apple, auth_user=self.u_apple
)
Paul "LeoNerd" Evans
committed
self.assertEquals(
state
)
@defer.inlineCallbacks
def test_get_allowed_state(self):
yield self.datastore.allow_presence_visible(
Paul "LeoNerd" Evans
committed
observed_localpart=self.u_apple.localpart,
observer_userid=self.u_banana.to_string(),
)
state = yield self.handler.get_state(
target_user=self.u_apple, auth_user=self.u_banana
)
Paul "LeoNerd" Evans
committed
self.assertEquals(
@defer.inlineCallbacks
def test_get_same_room_state(self):
self.room_members = [self.u_apple, self.u_clementine]
state = yield self.handler.get_state(
target_user=self.u_apple, auth_user=self.u_clementine
)
Paul "LeoNerd" Evans
committed
self.assertEquals(
Paul "LeoNerd" Evans
committed
state
)
@defer.inlineCallbacks
def test_get_disallowed_state(self):
self.room_members = []
yield self.assertFailure(
self.handler.get_state(
target_user=self.u_apple, auth_user=self.u_clementine
),
SynapseError
)
@defer.inlineCallbacks
def test_set_my_state(self):
yield self.handler.set_state(
target_user=self.u_apple, auth_user=self.u_apple,
Paul "LeoNerd" Evans
committed
state={"presence": UNAVAILABLE, "status_msg": "Away"})
Paul "LeoNerd" Evans
committed
self.assertEquals(
{"state": UNAVAILABLE,
"status_msg": "Away",
"mtime": 1000000},
(yield self.datastore.get_presence_state(self.u_apple.localpart))
Paul "LeoNerd" Evans
committed
self.mock_start.assert_called_with(self.u_apple,
Paul "LeoNerd" Evans
committed
state={
Paul "LeoNerd" Evans
committed
"presence": UNAVAILABLE,
Paul "LeoNerd" Evans
committed
"status_msg": "Away",
Paul "LeoNerd" Evans
committed
"last_active": 1000000, # MockClock
Paul "LeoNerd" Evans
committed
})
yield self.handler.set_state(
target_user=self.u_apple, auth_user=self.u_apple,
Paul "LeoNerd" Evans
committed
state={"presence": OFFLINE})
self.mock_stop.assert_called_with(self.u_apple)
Paul "LeoNerd" Evans
committed
class PresenceInvitesTestCase(PresenceTestCase):
@defer.inlineCallbacks
def setUp(self):
yield super(PresenceInvitesTestCase, self).setUp()
self.mock_start = Mock()
self.mock_stop = Mock()
self.handler.start_polling_presence = self.mock_start
self.handler.stop_polling_presence = self.mock_stop
@defer.inlineCallbacks
def test_invite_local(self):
# TODO(paul): This test will likely break if/when real auth permissions
# are added; for now the HS will always accept any invite
yield self.handler.send_invite(
observer_user=self.u_apple, observed_user=self.u_banana)
self.assertEquals(
[{"observed_user_id": "@banana:test", "accepted": 1}],
(yield self.datastore.get_presence_list(self.u_apple.localpart))
)
self.assertTrue(
(yield self.datastore.is_presence_visible(
observed_localpart=self.u_banana.localpart,
observer_userid=self.u_apple.to_string(),
))
)
self.mock_start.assert_called_with(
self.u_apple, target_user=self.u_banana)
@defer.inlineCallbacks
def test_invite_local_nonexistant(self):
yield self.handler.send_invite(
observer_user=self.u_apple, observed_user=self.u_durian)
self.assertEquals(
[],
(yield self.datastore.get_presence_list(self.u_apple.localpart))
)
@defer.inlineCallbacks
def test_invite_remote(self):
# Use a different destination, otherwise retry logic might fail the
# request
u_rocket = UserID.from_string("@rocket:there")
Paul "LeoNerd" Evans
committed
put_json = self.mock_http_client.put_json
put_json.expect_call_and_return(
Matthew Hodgson
committed
path="/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
content={
"observer_user": "@apple:test",
Paul "LeoNerd" Evans
committed
}
json_data_callback=ANY,
Paul "LeoNerd" Evans
committed
),
defer.succeed((200, "OK"))
)
self.assertEquals(
[{"observed_user_id": "@rocket:there", "accepted": 0}],
(yield self.datastore.get_presence_list(self.u_apple.localpart))
)
Paul "LeoNerd" Evans
committed
yield put_json.await_calls()
@defer.inlineCallbacks
def test_accept_remote(self):
# TODO(paul): This test will likely break if/when real auth permissions
# are added; for now the HS will always accept any invite
# Use a different destination, otherwise retry logic might fail the
# request
u_rocket = UserID.from_string("@rocket:moon")
Paul "LeoNerd" Evans
committed
put_json = self.mock_http_client.put_json
put_json.expect_call_and_return(
Matthew Hodgson
committed
path="/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
content={
Paul "LeoNerd" Evans
committed
"observed_user": "@apple:test",
}
json_data_callback=ANY,
Paul "LeoNerd" Evans
committed
),
defer.succeed((200, "OK"))
)
Paul "LeoNerd" Evans
committed
yield self.mock_federation_resource.trigger("PUT",
Matthew Hodgson
committed
"/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
_make_edu_json("elsewhere", "m.presence_invite",
content={
Paul "LeoNerd" Evans
committed
)
self.assertTrue(
(yield self.datastore.is_presence_visible(
observed_localpart=self.u_apple.localpart,
))
)
Paul "LeoNerd" Evans
committed
yield put_json.await_calls()
@defer.inlineCallbacks
def test_invited_remote_nonexistant(self):
# Use a different destination, otherwise retry logic might fail the
# request
u_rocket = UserID.from_string("@rocket:sun")
Paul "LeoNerd" Evans
committed
put_json = self.mock_http_client.put_json
put_json.expect_call_and_return(
Matthew Hodgson
committed
path="/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
content={
Paul "LeoNerd" Evans
committed
"observed_user": "@durian:test",
}
json_data_callback=ANY,
Paul "LeoNerd" Evans
committed
),
defer.succeed((200, "OK"))
Paul "LeoNerd" Evans
committed
yield self.mock_federation_resource.trigger("PUT",
Matthew Hodgson
committed
"/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
)
Paul "LeoNerd" Evans
committed
yield put_json.await_calls()
@defer.inlineCallbacks
def test_accepted_remote(self):
yield self.datastore.add_presence_list_pending(
observer_localpart=self.u_apple.localpart,
observed_userid=self.u_cabbage.to_string(),
)
Paul "LeoNerd" Evans
committed
yield self.mock_federation_resource.trigger("PUT",
Matthew Hodgson
committed
"/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
_make_edu_json("elsewhere", "m.presence_accept",
content={
"observer_user": "@apple:test",
"observed_user": "@cabbage:elsewhere",
}
Paul "LeoNerd" Evans
committed
)
self.assertEquals(
[{"observed_user_id": "@cabbage:elsewhere", "accepted": 1}],
(yield self.datastore.get_presence_list(self.u_apple.localpart))
)
self.mock_start.assert_called_with(
self.u_apple, target_user=self.u_cabbage)
@defer.inlineCallbacks
def test_denied_remote(self):
yield self.datastore.add_presence_list_pending(
observer_localpart=self.u_apple.localpart,
observed_userid="@eggplant:elsewhere",
)
Paul "LeoNerd" Evans
committed
yield self.mock_federation_resource.trigger("PUT",
Matthew Hodgson
committed
"/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
_make_edu_json("elsewhere", "m.presence_deny",
content={
"observer_user": "@apple:test",
"observed_user": "@eggplant:elsewhere",
}
Paul "LeoNerd" Evans
committed
)
self.assertEquals(
[],
(yield self.datastore.get_presence_list(self.u_apple.localpart))
)
@defer.inlineCallbacks
def test_drop_local(self):
yield self.datastore.add_presence_list_pending(
observer_localpart=self.u_apple.localpart,
observed_userid=self.u_banana.to_string(),
)
yield self.datastore.set_presence_list_accepted(
observer_localpart=self.u_apple.localpart,
observed_userid=self.u_banana.to_string(),
)
observer_user=self.u_apple,
observed_user=self.u_banana,
)
self.assertEquals(
[],
(yield self.datastore.get_presence_list(self.u_apple.localpart))
)
self.mock_stop.assert_called_with(
self.u_apple, target_user=self.u_banana)
@defer.inlineCallbacks
def test_drop_remote(self):
yield self.datastore.add_presence_list_pending(
observer_localpart=self.u_apple.localpart,
observed_userid=self.u_cabbage.to_string(),
)
yield self.datastore.set_presence_list_accepted(
observer_localpart=self.u_apple.localpart,
observed_userid=self.u_cabbage.to_string(),
)
yield self.handler.drop(
observer_user=self.u_apple,
observed_user=self.u_cabbage,
)
self.assertEquals(
[],
(yield self.datastore.get_presence_list(self.u_apple.localpart))
)
@defer.inlineCallbacks
def test_get_presence_list(self):
yield self.datastore.add_presence_list_pending(
observer_localpart=self.u_apple.localpart,
observed_userid=self.u_banana.to_string(),
Paul "LeoNerd" Evans
committed
)
yield self.datastore.set_presence_list_accepted(
observer_localpart=self.u_apple.localpart,
observed_userid=self.u_banana.to_string(),
)
presence = yield self.handler.get_presence_list(
observer_user=self.u_apple)
Paul "LeoNerd" Evans
committed
self.assertEquals([
{"observed_user": self.u_banana,
"presence": OFFLINE,
"accepted": 1},
Paul "LeoNerd" Evans
committed
], presence)
Paul "LeoNerd" Evans
committed
class PresencePushTestCase(MockedDatastorePresenceTestCase):
""" Tests steady-state presence status updates.
They assert that presence state update messages are pushed around the place
when users change state, presuming that the watches are all established.
These tests are MASSIVELY fragile currently as they poke internals of the
presence handler; namely the _local_pushmap and _remote_recvmap.
BE WARNED...
"""
PRESENCE_LIST = {
'apple': [ "@banana:test", "@clementine:test" ],
}
@defer.inlineCallbacks
def test_push_local(self):
self.room_members = [self.u_apple, self.u_elderberry]
self.datastore.set_presence_state.return_value = defer.succeed(
# TODO(paul): Gut-wrenching
self.handler._user_cachemap[self.u_apple] = UserPresenceCache()
Paul "LeoNerd" Evans
committed
self.handler._user_cachemap[self.u_apple].update(
{"presence": OFFLINE}, serial=0
)
apple_set = self.handler._local_pushmap.setdefault("apple", set())
apple_set.add(self.u_banana)
apple_set.add(self.u_clementine)
self.assertEquals(self.event_source.get_current_key(), 0)
yield self.handler.set_state(self.u_apple, self.u_apple,
Paul "LeoNerd" Evans
committed
{"presence": ONLINE}
)
Paul "LeoNerd" Evans
committed
# Apple sees self-reflection
Paul "LeoNerd" Evans
committed
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_apple, 0, None
)
self.assertEquals(self.event_source.get_current_key(), 1)
Paul "LeoNerd" Evans
committed
self.assertEquals(events,
[
{"type": "m.presence",
"content": {
"user_id": "@apple:test",
Paul "LeoNerd" Evans
committed
"presence": ONLINE,
Paul "LeoNerd" Evans
committed
"last_active_ago": 0,
Paul "LeoNerd" Evans
committed
msg="Presence event should be visible to self-reflection"
)
Paul "LeoNerd" Evans
committed
config = SourcePaginationConfig(from_key=1, to_key=0)
(chunk, _) = yield self.event_source.get_pagination_rows(
self.u_apple, config, None
)
self.assertEquals(chunk,
[
{"type": "m.presence",
"content": {
"user_id": "@apple:test",
"presence": ONLINE,
"last_active_ago": 0,
}},
]
)
Paul "LeoNerd" Evans
committed
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
# Banana sees it because of presence subscription
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_banana, 0, None
)
self.assertEquals(self.event_source.get_current_key(), 1)
self.assertEquals(events,
[
{"type": "m.presence",
"content": {
"user_id": "@apple:test",
"presence": ONLINE,
"last_active_ago": 0,
}},
],
msg="Presence event should be visible to explicit subscribers"
)
# Elderberry sees it because of same room
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_elderberry, 0, None
)
self.assertEquals(self.event_source.get_current_key(), 1)
self.assertEquals(events,
[
{"type": "m.presence",
"content": {
"user_id": "@apple:test",
"presence": ONLINE,
"last_active_ago": 0,
}},
],
msg="Presence event should be visible to other room members"
)
# Durian is not in the room, should not see this event
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_durian, 0, None
)
self.assertEquals(self.event_source.get_current_key(), 1)
self.assertEquals(events, [],
msg="Presence event should not be visible to others"
presence = yield self.handler.get_presence_list(
observer_user=self.u_apple, accepted=True)
Paul "LeoNerd" Evans
committed
self.assertEquals(
[
{"observed_user": self.u_banana,
Paul "LeoNerd" Evans
committed
{"observed_user": self.u_clementine,
Paul "LeoNerd" Evans
committed
],
presence
)
Paul "LeoNerd" Evans
committed
# TODO(paul): Gut-wrenching
banana_set = self.handler._local_pushmap.setdefault("banana", set())
banana_set.add(self.u_apple)
yield self.handler.set_state(self.u_banana, self.u_banana,
Paul "LeoNerd" Evans
committed
{"presence": ONLINE}
)
Paul "LeoNerd" Evans
committed
self.clock.advance_time(2)
presence = yield self.handler.get_presence_list(
observer_user=self.u_apple, accepted=True)
self.assertEquals([
Paul "LeoNerd" Evans
committed
{"observed_user": self.u_banana,
Paul "LeoNerd" Evans
committed
"presence": ONLINE,
Paul "LeoNerd" Evans
committed
"last_active_ago": 2000},
Paul "LeoNerd" Evans
committed
{"observed_user": self.u_clementine,
Paul "LeoNerd" Evans
committed
], presence)
Paul "LeoNerd" Evans
committed
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_apple, 1, None
)
self.assertEquals(self.event_source.get_current_key(), 2)
Paul "LeoNerd" Evans
committed
self.assertEquals(events,
[
{"type": "m.presence",
"content": {
"user_id": "@banana:test",
Paul "LeoNerd" Evans
committed
"presence": ONLINE,
Paul "LeoNerd" Evans
committed
"last_active_ago": 2000
@defer.inlineCallbacks
def test_push_remote(self):
Paul "LeoNerd" Evans
committed
put_json = self.mock_http_client.put_json
put_json.expect_call_and_return(
call("farm",
path=ANY, # Can't guarantee which txn ID will be which
data=_expect_edu("farm", "m.presence",
content={
"push": [
{"user_id": "@apple:test",
Paul "LeoNerd" Evans
committed
"presence": u"online",
Paul "LeoNerd" Evans
committed
"last_active_ago": 0},
Paul "LeoNerd" Evans
committed
}
json_data_callback=ANY,
Paul "LeoNerd" Evans
committed
),
defer.succeed((200, "OK"))
)
Paul "LeoNerd" Evans
committed
put_json.expect_call_and_return(
call("remote",
path=ANY, # Can't guarantee which txn ID will be which
data=_expect_edu("remote", "m.presence",
content={
"push": [
{"user_id": "@apple:test",
"presence": u"online",
"last_active_ago": 0},
],
}
json_data_callback=ANY,
Paul "LeoNerd" Evans
committed
),
defer.succeed((200, "OK"))
)
Paul "LeoNerd" Evans
committed
self.room_members = [self.u_apple, self.u_onion]
self.datastore.set_presence_state.return_value = defer.succeed(
{"state": ONLINE}
)
# TODO(paul): Gut-wrenching
self.handler._user_cachemap[self.u_apple] = UserPresenceCache()
Paul "LeoNerd" Evans
committed
self.handler._user_cachemap[self.u_apple].update(
{"presence": OFFLINE}, serial=0
)
Paul "LeoNerd" Evans
committed
apple_set = self.handler._remote_sendmap.setdefault("apple", set())
apple_set.add(self.u_potato.domain)
yield self.handler.set_state(self.u_apple, self.u_apple,
Paul "LeoNerd" Evans
committed
{"presence": ONLINE}
Paul "LeoNerd" Evans
committed
)
yield put_json.await_calls()
@defer.inlineCallbacks
def test_recv_remote(self):
# TODO(paul): Gut-wrenching
potato_set = self.handler._remote_recvmap.setdefault(self.u_potato,
set())
potato_set.add(self.u_apple)
self.room_members = [self.u_banana, self.u_potato]
self.assertEquals(self.event_source.get_current_key(), 0)
Paul "LeoNerd" Evans
committed
yield self.mock_federation_resource.trigger("PUT",
Matthew Hodgson
committed
"/_matrix/federation/v1/send/1000000/",
Paul "LeoNerd" Evans
committed
_make_edu_json("elsewhere", "m.presence",
content={
Paul "LeoNerd" Evans
committed
"last_active_ago": 1000},
Paul "LeoNerd" Evans
committed
)
Paul "LeoNerd" Evans
committed
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_apple, 0, None
)
self.assertEquals(self.event_source.get_current_key(), 1)
Paul "LeoNerd" Evans
committed
self.assertEquals(events,
[
{"type": "m.presence",
"content": {
"user_id": "@potato:remote",
Paul "LeoNerd" Evans
committed
"presence": ONLINE,
Paul "LeoNerd" Evans
committed
"last_active_ago": 1000,
Paul "LeoNerd" Evans
committed
self.clock.advance_time(2)
state = yield self.handler.get_state(self.u_potato, self.u_apple)
Paul "LeoNerd" Evans
committed
self.assertEquals(
Paul "LeoNerd" Evans
committed
state
)
Paul "LeoNerd" Evans
committed
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
@defer.inlineCallbacks
def test_recv_remote_offline(self):
""" Various tests relating to SYN-261 """
potato_set = self.handler._remote_recvmap.setdefault(self.u_potato,
set())
potato_set.add(self.u_apple)
self.room_members = [self.u_banana, self.u_potato]
self.assertEquals(self.event_source.get_current_key(), 0)
yield self.mock_federation_resource.trigger("PUT",
"/_matrix/federation/v1/send/1000000/",
_make_edu_json("elsewhere", "m.presence",
content={
"push": [
{"user_id": "@potato:remote",
"presence": "offline"},
],
}
)
)
self.assertEquals(self.event_source.get_current_key(), 1)
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_apple, 0, None
)
self.assertEquals(events,
[
{"type": "m.presence",
"content": {
"user_id": "@potato:remote",
"presence": OFFLINE,
}}
]
)
@defer.inlineCallbacks
def test_join_room_local(self):
self.room_members = [self.u_apple, self.u_banana]
self.assertEquals(self.event_source.get_current_key(), 0)
# TODO(paul): Gut-wrenching
self.handler._user_cachemap[self.u_clementine] = UserPresenceCache()
self.handler._user_cachemap[self.u_clementine].update(
{
Paul "LeoNerd" Evans
committed
"presence": PresenceState.ONLINE,
Paul "LeoNerd" Evans
committed
"last_active": self.clock.time_msec(),
}, self.u_clementine
)
yield self.distributor.fire("user_joined_room", self.u_clementine,
self.room_id
Paul "LeoNerd" Evans
committed
self.room_members.append(self.u_clementine)
Paul "LeoNerd" Evans
committed
(events, _) = yield self.event_source.get_new_events_for_user(
self.u_apple, 0, None
)
self.assertEquals(self.event_source.get_current_key(), 1)
Paul "LeoNerd" Evans
committed
self.assertEquals(events,
[
{"type": "m.presence",
"content": {
"user_id": "@clementine:test",
Paul "LeoNerd" Evans
committed
"presence": ONLINE,
Paul "LeoNerd" Evans
committed
"last_active_ago": 0,
@defer.inlineCallbacks
def test_join_room_remote(self):
## Sending local user state to a newly-joined remote user
Paul "LeoNerd" Evans
committed
put_json = self.mock_http_client.put_json
put_json.expect_call_and_return(
call("remote",
path=ANY, # Can't guarantee which txn ID will be which
data=_expect_edu("remote", "m.presence",
content={
"push": [
{"user_id": "@apple:test",
Paul "LeoNerd" Evans
committed
],
}
),
json_data_callback=ANY,
Paul "LeoNerd" Evans
committed
),
defer.succeed((200, "OK"))
)
put_json.expect_call_and_return(
call("remote",
path=ANY, # Can't guarantee which txn ID will be which
data=_expect_edu("remote", "m.presence",
content={
"push": [
{"user_id": "@banana:test",
Paul "LeoNerd" Evans
committed
],
}
),
json_data_callback=ANY,
Paul "LeoNerd" Evans
committed
),
defer.succeed((200, "OK"))
)
# TODO(paul): Gut-wrenching
self.handler._user_cachemap[self.u_apple] = UserPresenceCache()
self.handler._user_cachemap[self.u_apple].update(
Paul "LeoNerd" Evans
committed
{"presence": PresenceState.ONLINE}, self.u_apple)
self.room_members = [self.u_apple, self.u_banana]
yield self.distributor.fire("user_joined_room", self.u_potato,
self.room_id