wip tests
This commit is contained in:
parent
42f0ab1d84
commit
a7bf3f6f95
|
@ -253,20 +253,59 @@ class AppServiceHandlerTestCase(unittest.TestCase):
|
|||
},
|
||||
)
|
||||
|
||||
def test_notify_interested_services_ephemeral(self):
|
||||
def test_notify_interested_services_ephemeral_read_receipt(self):
|
||||
"""
|
||||
Test sending ephemeral events to the appservice handler are scheduled
|
||||
Test sending read receipts to the appservice handler are scheduled
|
||||
to be pushed out to interested appservices, and that the stream ID is
|
||||
updated accordingly.
|
||||
"""
|
||||
# Create an application service that is guaranteed to be interested in
|
||||
# any new events
|
||||
interested_service = self._mkservice(is_interested=True)
|
||||
services = [interested_service]
|
||||
|
||||
self.mock_store.get_app_services.return_value = services
|
||||
|
||||
# State that this application service has received up until stream ID 579
|
||||
self.mock_store.get_type_stream_id_for_appservice.return_value = make_awaitable(
|
||||
579
|
||||
)
|
||||
|
||||
# Set up a dummy event that should be sent to the application service
|
||||
event = Mock(event_id="event_1")
|
||||
self.event_source.sources.receipt.get_new_events_as.return_value = (
|
||||
make_awaitable(([event], None))
|
||||
)
|
||||
|
||||
self.handler.notify_interested_services_ephemeral(
|
||||
"receipt_key", 580, ["@fakerecipient:example.com"]
|
||||
)
|
||||
self.mock_scheduler.submit_ephemeral_events_for_as.assert_called_once_with(
|
||||
interested_service, [event]
|
||||
)
|
||||
self.mock_store.set_type_stream_id_for_appservice.assert_called_once_with(
|
||||
interested_service,
|
||||
"read_receipt",
|
||||
580,
|
||||
)
|
||||
|
||||
def test_notify_interested_services_ephemeral_to_device(self):
|
||||
"""
|
||||
Test sending read receipts to the appservice handler are scheduled
|
||||
to be pushed out to interested appservices, and that the stream ID is
|
||||
updated accordingly.
|
||||
"""
|
||||
# Create an application service that is guaranteed to be interested in
|
||||
# any new events
|
||||
interested_service = self._mkservice(is_interested=True)
|
||||
services = [interested_service]
|
||||
self.mock_store.get_app_services.return_value = services
|
||||
|
||||
# State that this application service has received up until stream ID 579
|
||||
self.mock_store.get_type_stream_id_for_appservice.return_value = make_awaitable(
|
||||
579
|
||||
)
|
||||
|
||||
# Set up a dummy event that should be sent to the application service
|
||||
event = Mock(event_id="event_1")
|
||||
self.event_source.sources.receipt.get_new_events_as.return_value = (
|
||||
make_awaitable(([event], None))
|
||||
|
|
258
tests/handlers/test_appservice_ephemeral.py
Normal file
258
tests/handlers/test_appservice_ephemeral.py
Normal file
|
@ -0,0 +1,258 @@
|
|||
# Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import Dict, Iterable, Optional, Tuple, Union
|
||||
from unittest.mock import Mock
|
||||
|
||||
import synapse.rest.admin
|
||||
import synapse.storage
|
||||
from synapse.appservice import ApplicationService
|
||||
from synapse.rest.client import login, receipts, room
|
||||
from synapse.util.stringutils import random_string
|
||||
from synapse.types import JsonDict
|
||||
|
||||
from tests import unittest
|
||||
|
||||
|
||||
class ApplicationServiceEphemeralEventsTestCase(unittest.HomeserverTestCase):
|
||||
servlets = [
|
||||
synapse.rest.admin.register_servlets_for_client_rest_resource,
|
||||
login.register_servlets,
|
||||
room.register_servlets,
|
||||
receipts.register_servlets,
|
||||
]
|
||||
|
||||
def prepare(self, reactor, clock, hs):
|
||||
# Mock the application service scheduler so that we can track any outgoing transactions
|
||||
self.mock_scheduler = Mock()
|
||||
self.mock_scheduler.submit_ephemeral_events_for_as = Mock()
|
||||
|
||||
hs.get_application_service_handler().scheduler = self.mock_scheduler
|
||||
|
||||
self.user1 = self.register_user("user1", "password")
|
||||
self.token1 = self.login("user1", "password")
|
||||
|
||||
self.user2 = self.register_user("user2", "password")
|
||||
self.token2 = self.login("user2", "password")
|
||||
|
||||
def test_application_services_receive_read_receipts(self):
|
||||
"""
|
||||
Test that when a user sends a read receipt in a room with another
|
||||
user, and that is in an application service's user namespace, that
|
||||
application service will receive that read receipt.
|
||||
"""
|
||||
(
|
||||
interested_service,
|
||||
_,
|
||||
) = self._register_interested_and_uninterested_application_services()
|
||||
|
||||
# Create a room with both user1 and user2
|
||||
room_id = self.helper.create_room_as(
|
||||
self.user1, tok=self.token1, is_public=True
|
||||
)
|
||||
self.helper.join(room_id, self.user2, tok=self.token2)
|
||||
|
||||
# Have user2 send a message into the room
|
||||
response_dict = self.helper.send(room_id, body="read me", tok=self.token2)
|
||||
|
||||
# Have user1 send a read receipt for the message with an empty body
|
||||
self._send_read_receipt(room_id, response_dict["event_id"], self.token1)
|
||||
|
||||
# user2 should have been the recipient of that read receipt.
|
||||
# Check if our application service - that is interested in user2 - received
|
||||
# the read receipt as part of an AS transaction.
|
||||
#
|
||||
# The uninterested application service should not have been notified.
|
||||
last_call = self.mock_scheduler.submit_ephemeral_events_for_as.call_args_list[
|
||||
0
|
||||
]
|
||||
service, events = last_call[0]
|
||||
self.assertEqual(service, interested_service)
|
||||
self.assertEqual(len(events), 1)
|
||||
self.assertEqual(events[0]["type"], "m.receipt")
|
||||
self.assertEqual(events[0]["room_id"], room_id)
|
||||
|
||||
# Assert that this was a read receipt from user1
|
||||
read_receipts = list(events[0]["content"].values())
|
||||
self.assertIn(self.user1, read_receipts[0]["m.read"])
|
||||
|
||||
# Clear mock stats
|
||||
self.mock_scheduler.submit_ephemeral_events_for_as.reset_mock()
|
||||
|
||||
# Send 2 pairs of messages + read receipts
|
||||
response_dict_1 = self.helper.send(room_id, body="read me1", tok=self.token2)
|
||||
response_dict_2 = self.helper.send(room_id, body="read me2", tok=self.token2)
|
||||
self._send_read_receipt(room_id, response_dict_1["event_id"], self.token1)
|
||||
self._send_read_receipt(room_id, response_dict_2["event_id"], self.token1)
|
||||
|
||||
# Assert each transaction that was sent to the application service is as expected
|
||||
self.assertEqual(2, self.mock_scheduler.submit_ephemeral_events_for_as.call_count)
|
||||
|
||||
first_call, second_call = self.mock_scheduler.submit_ephemeral_events_for_as.call_args_list
|
||||
service, events = first_call[0]
|
||||
self.assertEqual(service, interested_service)
|
||||
self.assertEqual(len(events), 1)
|
||||
self.assertEqual(events[0]["type"], "m.receipt")
|
||||
self.assertEqual(
|
||||
self._event_id_from_read_receipt(events[0]), response_dict_1["event_id"]
|
||||
)
|
||||
|
||||
service, events = second_call[0]
|
||||
self.assertEqual(service, interested_service)
|
||||
self.assertEqual(len(events), 1)
|
||||
self.assertEqual(events[0]["type"], "m.receipt")
|
||||
self.assertEqual(
|
||||
self._event_id_from_read_receipt(events[0]), response_dict_2["event_id"]
|
||||
)
|
||||
|
||||
def test_application_services_receive_to_device(self):
|
||||
"""
|
||||
Test that when a user sends a to-device message to another user, and
|
||||
that is in an application service's user namespace, that application
|
||||
service will receive it.
|
||||
"""
|
||||
(
|
||||
interested_service,
|
||||
_,
|
||||
) = self._register_interested_and_uninterested_application_services()
|
||||
|
||||
# Create a room with both user1 and user2
|
||||
room_id = self.helper.create_room_as(
|
||||
self.user1, tok=self.token1, is_public=True
|
||||
)
|
||||
self.helper.join(room_id, self.user2, tok=self.token2)
|
||||
|
||||
# Have user2 send a typing notification into the room
|
||||
response_dict = self.helper.send(room_id, body="read me", tok=self.token2)
|
||||
|
||||
# Have user1 send a read receipt for the message with an empty body
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"/rooms/%s/receipt/m.read/%s" % (room_id, response_dict["event_id"]),
|
||||
access_token=self.token1,
|
||||
)
|
||||
self.assertEqual(channel.code, 200)
|
||||
|
||||
# user2 should have been the recipient of that read receipt.
|
||||
# Check if our application service - that is interested in user2 - received
|
||||
# the read receipt as part of an AS transaction.
|
||||
#
|
||||
# The uninterested application service should not have been notified.
|
||||
service, events = self.mock_scheduler.submit_ephemeral_events_for_as.call_args[
|
||||
0
|
||||
]
|
||||
self.assertEqual(service, interested_service)
|
||||
self.assertEqual(events[0]["type"], "m.receipt")
|
||||
self.assertEqual(events[0]["room_id"], room_id)
|
||||
|
||||
# Assert that this was a read receipt from user1
|
||||
read_receipts = list(events[0]["content"].values())
|
||||
self.assertIn(self.user1, read_receipts[0]["m.read"])
|
||||
|
||||
def _register_interested_and_uninterested_application_services(
|
||||
self,
|
||||
) -> Tuple[ApplicationService, ApplicationService]:
|
||||
# Create an application service with exclusive interest in user2
|
||||
interested_service = self._make_application_service(
|
||||
namespaces={
|
||||
ApplicationService.NS_USERS: [
|
||||
{
|
||||
"regex": "@user2:.+",
|
||||
"exclusive": True,
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
uninterested_service = self._make_application_service()
|
||||
|
||||
# Register this application service, along with another, uninterested one
|
||||
services = [
|
||||
uninterested_service,
|
||||
interested_service,
|
||||
]
|
||||
self.hs.get_datastore().get_app_services = Mock(return_value=services)
|
||||
|
||||
return interested_service, uninterested_service
|
||||
|
||||
def _make_application_service(
|
||||
self,
|
||||
namespaces: Optional[
|
||||
Dict[
|
||||
Union[
|
||||
ApplicationService.NS_USERS,
|
||||
ApplicationService.NS_ALIASES,
|
||||
ApplicationService.NS_ROOMS,
|
||||
],
|
||||
Iterable[Dict],
|
||||
]
|
||||
] = None,
|
||||
supports_ephemeral: Optional[bool] = True,
|
||||
) -> ApplicationService:
|
||||
return ApplicationService(
|
||||
token=None,
|
||||
hostname="example.com",
|
||||
id=random_string(10),
|
||||
sender="@as:example.com",
|
||||
rate_limited=False,
|
||||
namespaces=namespaces,
|
||||
supports_ephemeral=supports_ephemeral,
|
||||
)
|
||||
|
||||
def _send_read_receipt(self, room_id: str, event_id_to_read: str, tok: str) -> None:
|
||||
"""
|
||||
Send a read receipt of an event into a room.
|
||||
|
||||
Args:
|
||||
room_id: The room to event is part of.
|
||||
event_id_to_read: The ID of the event being read.
|
||||
tok: The access token of the sender.
|
||||
"""
|
||||
channel = self.make_request(
|
||||
"POST",
|
||||
"/rooms/%s/receipt/m.read/%s" % (room_id, event_id_to_read),
|
||||
access_token=tok,
|
||||
content="{}",
|
||||
)
|
||||
self.assertEqual(channel.code, 200, channel.json_body)
|
||||
|
||||
def _event_id_from_read_receipt(self, read_receipt_dict: JsonDict):
|
||||
"""
|
||||
Extracts the first event ID from a read receipt. Read receipt dictionaries
|
||||
are in the form:
|
||||
|
||||
{
|
||||
'type': 'm.receipt',
|
||||
'room_id': '!PEzCqHyycBVxqMKIjI:test',
|
||||
'content': {
|
||||
'$DETIeTEH651c1N7sP_j-YZiaQqCaayHhYwmhZDVWDY8': { # We want this
|
||||
'm.read': {
|
||||
'@user1:test': {
|
||||
'ts': 1300,
|
||||
'hidden': False
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Args:
|
||||
read_receipt_dict: The dictionary returned from a POST read receipt call.
|
||||
|
||||
Returns:
|
||||
The (first) event ID the read receipt refers to.
|
||||
"""
|
||||
return list(read_receipt_dict["content"].keys())[0]
|
||||
|
||||
# TODO: Test that ephemeral messages aren't sent to application services that have
|
||||
# ephemeral: false
|
|
@ -230,7 +230,7 @@ class RestHelper:
|
|||
custom_headers: Optional[
|
||||
Iterable[Tuple[Union[bytes, str], Union[bytes, str]]]
|
||||
] = None,
|
||||
):
|
||||
) -> JsonDict:
|
||||
if body is None:
|
||||
body = "body_text_here"
|
||||
|
||||
|
@ -257,7 +257,7 @@ class RestHelper:
|
|||
custom_headers: Optional[
|
||||
Iterable[Tuple[Union[bytes, str], Union[bytes, str]]]
|
||||
] = None,
|
||||
):
|
||||
) -> JsonDict:
|
||||
if txn_id is None:
|
||||
txn_id = "m%s" % (str(time.time()))
|
||||
|
||||
|
|
|
@ -320,7 +320,7 @@ class HomeserverTestCase(TestCase):
|
|||
def wait_for_background_updates(self) -> None:
|
||||
"""Block until all background database updates have completed."""
|
||||
while not self.get_success(
|
||||
self.store.db_pool.updates.has_completed_background_updates()
|
||||
self.hs.get_datastore().db_pool.updates.has_completed_background_updates()
|
||||
):
|
||||
self.get_success(
|
||||
self.store.db_pool.updates.do_next_background_update(100), by=0.1
|
||||
|
|
|
@ -236,7 +236,7 @@ def setup_test_homeserver(
|
|||
else:
|
||||
database_config = {
|
||||
"name": "sqlite3",
|
||||
"args": {"database": ":memory:", "cp_min": 1, "cp_max": 1},
|
||||
"args": {"database": "test.db", "cp_min": 1, "cp_max": 1},
|
||||
}
|
||||
|
||||
if "db_txn_limit" in kwargs:
|
||||
|
|
Loading…
Reference in a new issue