wip tests

This commit is contained in:
Andrew Morgan 2021-11-11 07:21:28 +00:00
parent 42f0ab1d84
commit a7bf3f6f95
5 changed files with 304 additions and 7 deletions

View file

@ -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))

View 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

View file

@ -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()))

View file

@ -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

View file

@ -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: